1. 多继承
继承的概念已经融入了面向对象编程理念之中, 所有面向对象的编程语言都希望程序员灵活运用类和继承. 但多继承却被很多现代编程语言所禁止, 如Java, C#, Ruby, 这不是没有缘由的, 因为多继承会增加程序的复杂性和含糊性
即便有这么多缺陷, 但还是有一些编程语言允许程序员进行多继承, 如C++和Python.
本文主要讲解多继承中的钻石问题(diamond inheritance).
2. C++钻石问题
2.1 错误示例
class Base { private: int p = 100;
public: int getParam() { return p; }; };
class A: public Base { };
class B: public Base { };
class AB: public A, public B { };
int main() { AB ab; int p = ab.getParam(); }
|
从代码中我们可以清楚的看出问题: 当我们实例化AB类时, 所调用的函数getParam()是模糊的, 不确定调用A还是B的函数. 针对这个问题, C++给出了解决方案: 使用virtual(虚基类)
2.2 正确示例
class Base { private: int p = 100;
public: int getParam() { return p; }; };
class A: virtual public Base { };
class B: virtual public Base { };
class AB: public A, public B { };
int main() { AB ab; int p = ab.getParam(); }
|
3. Python钻石问题
3.1 错误示例
class Base(object): def __init__(self): print 'Base' self.p = 100
def getParam(self): print self.p
class A(Base): def __init__(self): Base.__init__(self) print 'A'
class B(Base): def __init__(self): Base.__init__(self) print 'B'
class AB(A, B): def __init__(self): A.__init__(self) B.__init__(self) print 'AB'
ab = AB() print AB.mro() ab.getParam()
|
从代码结果我们可以发现, Base的初始化函数运行了两遍, 这可能会引起程序的错误.
Pyhton给出的结果方案是使用super来避开初始Base两次.
3.2 正确示例
class Base(object): def __init__(self): print 'Base'
class A(Base): def __init__(self): super(A, self).__init__() print 'A'
class B(Base): def __init__(self): super(B, self).__init__() print 'B'
class AB(A, B): def __init__(self): super(AB, self).__init__() print 'AB'
ab = AB() print AB.mro()
|
当我们在运行super(AB, self).__init__()
时, 首先获取self的mro并从左往右开始依次寻找__init__
, 找到A并将A的__init__
绑定到self对象中. 而A的__init__
又是Base的__init__
.
当初始化B类时, 不会再初始化Base, 因为super中的mro只会运行一次.