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;那么它没有给出任何错误。