当我使用Objective-C点表示法来设置子类成员时,我会得到一个编译器错误



Enrivoment:Mac OS X 10.6.8 Xcode 3.2.3

@interface A : NSObject
@end
@implementation: A
@end
@interface B : A
{
    int b;
}
@property int b;
@end
@implementation B
@synthesize b;
@end
#import "A.h"
#import "B.h"
int main()
{
    A *pa;
    pa = [[B alloc] init];
    pa.b = 3; /*here I get a error: request for member 'b' in something 
                not a structure or union. */
    [pa setB: 3]; // this works.
    return 0;
}

那么,为什么这是一个错误呢?正如我所知,点表示法和括号表示法是一样的。

pa是指向类A的实例的指针,该实例没有属性b。您需要将其强制转换为指向B:的指针

((B*)pa).b = 3;

此行没有编译器错误,但有关于未知选择器的警告(因为pa是指向A的指针):

[pa setB: 3];

但在属性的情况下,编译器需要知道它是什么类型的属性,才能生成适当的消息。

在运行时,它们也会这样做,是的,但您仍处于编译时。

在编译时,如果你使用点表示法,编译器不会让你逃脱它认为可能不起作用的惩罚。由于您通过基类类型A访问对象,但属性位于类型B上,因此编译器会报告一个错误。

另一方面,如果使用括号表示法,编译器则不那么坚决,只打印警告。它承认您可能知道您在做什么:-),但它让您知道它在类A的接口中没有看到名为setB:的方法。

要消除警告,请声明您的变量lke this:

id pa;

使用类型id(翻译为"指向对象的指针")可以在没有警告的情况下向对象发送任何消息,因为现在编译器对对象的类型不做任何假设。您已经进入了全动态语言Objective-C的奇妙世界:-)

您已将pa声明为A*类型

然后分配B并分配给pa。由于B是a的子类,所以它是有效的。

然后你引用pa.b.A*(这是变量的类型)没有成员b。如果你强制转换它,它应该可以工作:

((*B)pa).b = 3;

setB起作用,因为编译器将尝试发送选择器setB:,对象可能会也可能不会对其做出响应。

不过你可能会收到警告。

您定义了一个类的对象并分配了类b的对象,因此当您也要使用after类型时,请强制转换该指针。

((B*)pa).B=3;那么它没有给出任何错误。

最新更新