点(“。”)运算符和箭头(“ – >”)运算符在C和Objective-C中使用
我试图围绕C和Objective-C中的一些使用和语法差异来解决问题。 特别是,我想知道在C和Objective-C中点运算符和箭头运算符的使用方式(以及为什么)有所不同。 这是一个简单的例子。
C代码:
// declare a pointer to a Fraction struct Fraction *frac; ... // reference an 'instance' variable int n = (*frac).numerator; // these two expressions int n = frac->numerator; // are equivalent
Objective-C代码:
// declare a pointer to a Fraction Fraction *frac = [[Fraction alloc] init]; ... // reference an instance variable int n = frac.numerator; // why isn't this (*frac).numerator or frac->numerator??
所以,看看这两个程序中的frac
是如何相同的(即它是一个指向Fraction对象或结构的指针),为什么在访问属性时他们使用不同的语法? 特别是在C语言中, numerator
属性是用frac->numerator
numerator
来访问的,而在Objective-C中,它是用点运算符和frac.numerator
来访问的。 由于frac
是两个程序的指针,为什么这些expression不同呢? 任何人都可以帮我澄清这一点?
在两个scheme中frac
实际上是不一样的。
交换Fraction
是一个struct
,它是一个没有重载操作符的基types,只能真正的被构造和破坏。 如果你在结构上定义了函数或者字段,那么在C
访问这些属性的方法是使用点( .
)运算符。 当你使用struct
时,Objective-C维护这个运算符。 为方便起见,您可以使用箭头( ->
)运算符(您提到的两个等效expression式)执行解引用和点运算。 Objective-C在访问struct
时也保留了这一点。
然而,在你的例子中的一个Objective-C Fraction
可能(至less会假设)一个至less是typesid
的指针,它只是一个类名和指向该类下的类的实例的指针。 它也很可能是NSObject
或NSProxy
一个子类。 这些Objective-C类是特别的,因为它们在C
结构之上有一整层预定义的操作(如果你真的想深入研究它,那么你可以看一下Objective-C运行时参考 )。 同样重要的是要注意,一个Objective-C类总是一个指针 。
其中最基本的操作是objc_msgSend
。 当我们对这些types的对象进行操作时,Objective-C编译器将一个点( .
)运算符或方括号语法( [object method]
)解释为一个objc_msgSend
方法调用。 有关这里实际发生情况的更多详细信息,请参阅负责监督Obj-C运行时开发的苹果工程师Bill Bumgarner撰写的这一系列文章 。
箭头( ->
)运算符不是真的应该用在Objective-C对象上。 就像我所说的,Objective-C类实例是一个C结构,增加了额外的通信层,但是当使用箭头时,这个通信层基本上被绕过了。 例如,如果打开Xcode并键入[UIApplication sharedApplication]->
,然后调出方法完成列表,您将看到:
在这里你可以看到一些普通的字段,我们通常用方括号语法来访问(比如[[UIApplication sharedApplication] delegate]
)。 但是,这些特定的项目是存储其各自Objective-C属性值的C
字段。
所以,大致可以这样想:
在C对象上的点运算符
- (在运行时)字段的返回值
C对象上的箭头运算符(指针)
- 取消引用指针
- 返回该字段的值
点操作符/方括号在Objective-C对象(指针)
- (在编译时)replace为调用
objc_msgSend
- (在运行时)查找Obj-C类的定义,如果出现错误则抛出exception
- 取消引用指针
- 返回该字段的值
一个Objective-C对象上的箭头运算符(指针)
- (在运行时)解引用指针
- 返回该字段的值
现在我在这里肯定是简单化了,但总结一下:在这两种情况下,箭头运算符看起来基本上是一样的,但点运算符在Objective-C中有一个额外/不同的含义。
点符号是一个deviseselect。 因为我们总是处理objc实例的指针,所以我猜devise师需要一些熟悉的东西,这也不会破坏现有的程序。 它是在ObjC 2中推出的 – 几年前。 在此之前,你总是不得不使用括号来传递消息。
点符号虽然有所作为 – 它不是直接访问,而是一个消息 。
那是:
obj.property = val; // is the same as: [obj setProperty:val]; // and not: obj->property = val; val = obj.property; // is the same as: val = [obj property]; // and not: val = obj->property;
你仍然可以写obj->ivar
来访问一个指向对象成员的指针(如果可见的话)。
在你的第一个例子中, Fraction
是一个结构。 在第二个例子中, Fraction
是一个Objective-C类(在iOS中可能是NSObject
一个子类)。
C ++ 不允许 operator .
重载operator .
。 因此,如果没有附加信息,则可以推断出您所看到的点符号是集成到Objective-C中的另一种语言结构,而不是C / C ++定义的或重载的运算符。
实际上,点符号仅仅是实现者select的属性访问的简写的devise特征,完全等价于方括号的getter:
myObjCVar.prop == [myObjCVar prop];
对象上的点运算符是访问对象属性的特殊语法。 它在幕后调用属性的getter或setter。 所以,例如, [@"hello" length]
和@"hello".length
是相等的*。 对于所有其他types,点与C点相同,箭头始终相同。
*注意:访问器方法不总是与属性名称相同。 如果它是一个声明的属性,并且该声明指定了一个特殊的getter或setter方法,则将使用该方法。
C中的点和箭号表示法与Objective-C(严格超集)中的相同。 我认为需要区分的基本差异是结构和Objective-C对象之间的区别。
Objective-C中用于对象的点符号用于Objective-C 2.0中引入的属性。 但是,对于结构体,Objective-C和C之间的 – >和点符号是相同的。