关于Objective-C和C++中的继承及其区别
最近在看一个开源项目的代码(iOS上的抽屉式视图MMDrawerController,Github地址:https://github.com/mutualmobile/MMDrawerController),当看到其中一个地方的时候,发现自己的基础知识真是太渣了。。。
问题是这样的:类B有两个实例方法method1和method2,method1中调用了method2;类D继承自类A,并实现了自己的method1和method2,然后在D的method1中通过super调用父类A的method1。那么,最后执行的是父类A的method2还是子类B的method2呢?
经过一番验证,自然是得到了答案。然后我有想到了下面几个问题:
- 同样学得半吊子的C++里,这种情况是调用method1还是method2来着?
- Objective-C中,如果method2是私有方法,又会如何?
- 对于2中的情况,C++中是什么样的?
话不多说,针对原先的问题,代码如下:
@interface B : NSObject - (void)method1; - (void)method2; @end
@implementation B - (void)method1 { [self method2]; } - (void)method2 { NSLog(@"Base method2."); } @end
@interface D : B
@end
@implementation D
- (void)method1
{
[super method1];
}
- (void)method2
{
NSLog(@"Derived method2.");
}
@end
在main函数中执行:
D *d = [[D alloc] init];
[d method1];
结果为:Derived method2. 可以看出,调用的是子类D的method2方法。
那么,在C++中又会如何呢?同样用代码来说话:
class B {
public:
void method1();
void method2();
};
class D : public B {
public:
void method1();
void method2();
};
void B::method1()
{
method2();
}
void B::method2()
{
cout << "B" << endl;
}
void D::method1()
{
B::method1();
}
void D::method2()
{
cout << "D" << endl;
}
int main(int argc, const char * argv[])
{
D *d = new D();
d->method1();
delete d;
return 0;
}
执行结果为:B ,调用的是父类的方法。
可是如果要像Objective-C中一样调用子类D的方法,该怎么做呢?虽然我的C++是半吊子,还是想起了虚函数。在父类的method2声明前加上virtual关键字,然后执行的结果就会变成 D 了。
(这时会发现,我这个例子和通常C++参考书里讲虚函数的例子有所不同,那些例子类似于:
B *d = new D();
d->method2();
即用父类指针指向子类对象,然后调用一个虚函数。
两个例子虽然长得不同,不过本质还是一样的嘛,都是根据对象的实际类型调用相应的方法。)
好了,进入下一个问题:如果method2是私有方法会如何?
修改代码,注释掉method2得声明:
@interface B : NSObject
- (void)method1;
//- (void)method2;
@end
运行后会发现,调用依然的是子类的方法。虽然method2是私有的,还是被子类覆盖掉了。。。这点需要注意,尤其是在子类化苹果的框架和第三方类库的时候。
然后看C++,如果加了virtual的话,同样会被覆盖,不过private方法谁闲着没事加个virtual呢。
综上,Objective-C中的方法相当于自动加了virtual(如果要避开这种多态的特性需要进行合理的设计);子类化时需要避免可能对父类私有方法的覆盖。