这可能是一个基本问题,但我没有在任何地方看到它.在C++中,假设我有以下代码:
#include <iostream>
using namespace std;
class B {
public:
void f();
};
class C {
public:
void f();
};
class D : public B, public C{
public:
void f();
};
void B::f(){cout << "bbb" << endl;}
void C::f(){cout << "ccc" << endl;}
void D::f(){cout << "ddd" << endl;}
int main () {
B *d = new D;
delete d;
d->f();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这很好,输出"bbb".但是,如果我要改变顺序
class D : public B, public C{
Run Code Online (Sandbox Code Playgroud)
至
class D : public C, public B{
Run Code Online (Sandbox Code Playgroud)
我会得到一个"Aborted(core dumped)"错误.这是什么原因?有人可以进一步解释基类顺序的重要性吗?
我知道这是多重继承,但我避免钻石问题所以不确定发生了什么.
该类B不是多态的(例如,不提供任何virtual方法).因此,编译器假定d指向的对象的动态类型是B,并且它尝试根据该B对象的地址删除内存,该地址不再与实际D对象的地址匹配.正如人们所写:
D * d = new D;
delete static_cast<B *>(d);
Run Code Online (Sandbox Code Playgroud)
那里有未定义的行为.当继承的类的顺序D是B,为什么它似乎工作C,可能在你的情况下B,D对象部分的地址碰巧与D对象本身的地址相同.没有析构函数(显式或隐式)定义,因此只调用了一个释放函数,它可能接受了相应分配函数提供的指针.
另请注意,根据[basic.life]
类似地,在对象的生命周期开始之前但在对象将占用的存储已经被分配之后,或者在对象的生命周期结束之后并且在对象占用的存储被重用或释放之前,任何引用的glvalue之前可以使用原始对象,但仅限于有限的方式.对于正在构建或销毁的对象,请参阅[class.cdtor].否则,这样的glvalue指的是已分配的存储([basic.stc.dynamic.deallocation]),并且使用不依赖于其值的glvalue的属性是明确定义的.如果出现以下情况,该程
- glvalue用于访问对象,或
- glvalue用于调用对象的非静态成员函数,或
- glvalue绑定到对虚基类([dcl.init.ref])的引用,或
- glvalue用作dynamic_cast的操作数或typeid的操作数.
因此d->f();,delete d;在代码中调用after 也会导致未定义的行为.
| 归档时间: |
|
| 查看次数: |
138 次 |
| 最近记录: |