Objective-C学习笔记之面向对象编程是本文要介绍的内容,主要详细的介绍了面向对象编程的内容,对于资深的C++程序员来说,面向对象编程不是什么新鲜的概念,类、对象、实例、方法这些概念就不再冗述了。和上一篇 Objective-C学习中对 C语言的扩展一样,这篇主要侧重于Objective-C中的OOP,有哪些与我们熟识的C++不同的概念。
- Point : NSObject
- {
- int X;
- int Y;
- }
- - (void) SetX: (int) X;
- - (void) SetY: (int) Y;
- - (void) Show;
- // Point
下面进行逐句分析。
“Point”告诉编译器:“这是为名为Point的新类定义的接口。”,而后面的“NSObject”告诉编译器,Point类是基于 NSObject类的。该语句表明每个Point类都是一个NSObject,并且每个Point都将继承NSObject类定义的所有行为。
花括号中的内容是用于大量创建新Point对象的模板。它表明,创建新Point对象时,该对象由两个元素构成——X和Y,每个创建出来的Point类对象都将拥有自己的X和Y。
随后的代码看起来像是C函数原型,在Objective-C中,它们称为方法声明。方法声明指出每种方法的名称、方法返回值的类型和某些参数。
前面的短线“-”表明这是Objective-C方法的声明,这是一种区分函数原型与方法声明的方式。
短线后面是方法的返回类型,位于圆括号中,void表示无返回值。Objective-C方法可以返回与C函数相同的类型:标准类型(整型、浮点型和字符型)、指针、对象引用和结构。
方法类型之后是方法名称,如果方法使用参数,在名称的结尾处需要使用冒号。这个冒号是名称的一部分,它告诉编译器后面会出现参数。
参数的类型是在圆括号中指定的,紧随其后的是参数名称。
最后的“Point
- - (void) SetX: (int) thisX
- {
- X = thisX;
- } // SetX
- - (void) SetY: (int) thisY
- {
- X = thisY;
- } // SetY
- - (void) Show
- {
- NSLog(Point at (%d, %d)", X, Y);
- } // Show
- // Point
下面进行逐句分析。
@implementation是一个编译器指令,表明它将为某个类提供代码。类名(Point)出现在@implementation之后,该行的结尾处没有分号。
接下来是各个方法的定义,它们不必按照在@interface指令中的顺序出现。你甚至可以在@implementation中定义那些在@interface中无相应声明的方法。可以把它们看成是私有方法,仅在类的实现中使用。
方法定义中的第一行看上去与@interface部分的声明非常类似,二者间的主要差别就是结尾处没有分号,另外还需要注意到我们将方法的参数重新命名了,@interface部分的方法声明中使用了名称X和Y,是为了确切告诉读者参数的用处。在具体实现中,我们必须区分参数名称和实例变量名称,所以需要将参数重命名。
SetX方法和SetY方法的结构几乎一样,对于Show方法需要注意,方法名的结尾处没有冒号,说明它不使用任何参数。
最后的“@end”代码告诉编译器,我们已经完成了Point类的实现。
实例化对象
实例化对象就是根据我们前面写好的声明创建一个新对象。为了创建新的对象,我们先来熟悉一个新的操作符——“[]”操作符。
在C语言中,程序员使用方括号引用数组元素。而在Objective-C中,方括号还有其他意义:它们用于向某个对象发送消息,通知其执行某种操作。在在方括号内,第一项是对象,其余部分是你需要发送的消息。例句如下:
- [Point new]
Objective-C具有一个极好的特性,你可以把类当成对象来向类发送消息。在本例中,我们就是向Point类发送new消息,通知Point类创建一个新对象。以下是完整的实例化对象代码。
- int main (int argc, const char* argv[]){ id thisPoint;
- thisPoint = [Point new];
- [thisPoint SetX: 0];
- [thisPoint SetY: 0];
- [thisPoint Show];
- }
- // main
下面进行逐句分析。
这个main()函数和普通C程序中的main()函数没有什么区别,参数argc保存启动参数的数量,因为程序名常用作启动参数传递,所以argc通常为1或更大。参数argv数组用于保存启动参数,argv[0]通常就是程序名,如果有其他启动参数,依次存放在argv[1]、argv[2]等等。
id代表identifier,是一种泛型,用于表示任何种类的对象。实际上,id就是指向某个对象的指针。
通过给Point类发送new消息,创建了一个Point类的实例,thisPoint中保存的就是指向这个市里的指针。
接下来就是通过给thisPoint对象发送SetX和SetY消息来设定其元素X和Y。需要注意到,和方法声明中类似,[]操作符发送给对象的消息需要携带参数时,在消息之后需要使用冒号,而携带的参数就跟随在冒号的后面。
最后就是通过给thisPoint对象发送Show消息显示其相关信息。同样需要注意,当发送的消息没有参数时,后面千万不可使用冒号。
继承
编写面向对象的程序时,你所创建的类和对象之间存在一定的关系。它们协同工作才能实现程序相应的功能。处理类和对象间的关系时,OOP有个很重要的特性叫做继承,使用继承可以定义一个具有原有类所有功能的新类。
在前文的@interface部分声明新类的时候,其实已经用到了继承的语法。
- @interface Point : NSObject
如上例中所示,冒号后的标识符就是需要继承的类。在Objective-C中,可以从非类中继承对象,但如果使用Cocoa,会希望从NSObject继承对象,因为NSObject提供了大量有用的特性。@interface部分最简单的继承代码可以如下所示:
- @interface MyPoint : Point@end // MyPoint
这时,MyPoint类就继承了Point类的所有数据成员和方法。在下面的文字中,我们统一用超类来描述所继承的类,用子类来描述实施继承的类。这里Point就是MyPoint的超类,而MyPoint就是Point的子类。
我们在写新的子类时,有时为了在类中引入某个独特的特性,需要添加新方法。还有些时候,可能需要替换或增强由这个新类的某个超类所定义的现有方法。
Objective-C提供某种方法来重新方法,并且仍然调用超类的实现方式。为了调用继承方法的实现,需要使用super作为方法调用的目标。
继续沿用前面给出的例子,假设我们发现之前采用的坐标有偏差,实际上的X坐标应为原有的X-10。我们便可在子类MyPoint中对Point类的Show()方法进行如下重写。
- @implementation MyPoint
- - (void) Show{ XX = X - 10; [super Show];
- }
- // Show @end // MyPoint
从上面的代码中,我们通过向super发送Show消息使用了超类的相应代码。
这里的super既不是参数也不是实例变量,向super发送消息时,实际上是在请求Objective-C向该类的超类发送消息。如果超类中没有定义该消息,Objective-C将按照惯常的方式在继承链中继续查找对应的消息。
小结:详解Objective-C学习笔记之面向对象编程的内容介绍完了,希望本文对你有所帮助。