最近在看一个开源项目的代码(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(如果要避开这种多态的特性需要进行合理的设计);子类化时需要避免可能对父类私有方法的覆盖。