概要
多继承踩过的坑看这一篇就够~
技术细节
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首地址有偏移,现在加了虚析构函数(普通析构无法修改偏移地址),在虚析构函数结束时会把偏移过的地址改回原样,地址对了回收内存自然也对了。
本文主要介绍C++多继承存在的问题及解决办法。多继承可能出现二义性错误,需加父类作用域区分;QT的moc文件只认多继承列表中的第一个父类,信号槽失效时需检查位置。此外,还阐述了父类析构不加virtual导致程序崩溃的原因及加虚析构函数后正常运行的原理。

被折叠的 条评论
为什么被折叠?



