概要
多继承踩过的坑看这一篇就够~
技术细节
1、多继承下同名变量问题处理:
class Base1 { public: Base1() :A(10) {} int A; }; class Base2 { public: Base2() :A(100) {} int A; }; class Son : public Base1, public Base2 { }; int main() { Son s; //s.A; //两个父类都有A,不知道调用哪个父类的A,出现二义性错误 s.Base1::A; //10 }
多继承存在一个问题就是可能多个父类有相同的成员变量,那么子类直接调用父类变量时就不知道调用哪个父类的变量,出现二义性错误,这时候必须加父类作用域进行区分。
2、多继承下信号槽问题:
QT的moc文件只认多继承列表中的第一个父类,如果使用过程中出现信号槽失效的问题,需要查看包含信号槽的父类是否放在多继承列表中的第一个位置。
3、多继承下的多态内存释放问题:
易错!!!
class Animal1 { public: virtual void fun1() = 0; ~Animal1() { cout << "Animal1析构" << endl; } }; class Animal2 { public: virtual void fun2() = 0; ~Animal2() { cout << "Animal2析构" << endl; } }; class cat : public Animal1, public Animal2 { public: virtual void fun1() {} virtual void fun2() {} ~cat() { cout << "cat析构" << endl; } }; int main() { Animal1* animal1 = new cat(); Animal2* animal2 = new cat(); delete animal1; delete animal2; }
如果直接运行程序,在执行到delete animal2时程序会出现如下崩溃:
解决办法:父类析构加上virtual变为虚析构,打印如下:
原因:
如果父类析构不加virtual,delete animal1时是没有错误的,错误出现再delete animal2。原因很好猜到,animal1所指的地址就是Cat对象的首地址,所以delete animal1可以正常运行;但是animal2 所指的地址不是Cat对象的首地址,由于这里是多继承(除了第一个父类,后面继承的父类地址相对于子类有偏移),animal2所指的地址相对Cat对象的首地址有偏移,编译器发现它自己没有给这个地址分配空间,所以就报错了。
为什么加了虚析构函数后运行正常呢?原因也很简单,delete这个运算符,是先调用析构函数,再回收内存。前面是没有虚析构函数,但animal1指向Cat首地址所以能顺利释放内存,animal2指向地址相对Cat首地址有偏移,现在加了虚析构函数(普通析构无法修改偏移地址),在虚析构函数结束时会把偏移过的地址改回原样,地址对了回收内存自然也对了。