我正在编写一个类(析构函数是虚拟的),只能使用recycleler类的对象删除哪些对象。但是我发现任何人都可以在不知道我的回收者类的情况下删除该类的对象。
请考虑以下示例:
class A
{
public:
A() {qDebug() << "cTor: A";}
protected:
virtual ~A() {qDebug() << "dTor: A";}
};
class B
{
public:
virtual ~B() {cout << "dTor: B";}
protected:
B() {cout << "cTor: B";}
};
A *a = new A;
delete (B*)a; // How is this possible !!??
输出:
cTor: A
dTor: A
如果可能的话,如果不使A
的析构函数的最终子类非虚拟化,我该怎样做才能防止这种情况?
答案 0 :(得分:2)
对于上面提到的情况,你很幸运,B的析构函数的地址与指针的偏移量相同。
虚拟析构函数只是对象的vftable中的另一个条目。如果你只是访问内存地址,你可以调用任何析构函数(无论他是多么私密)。
这是一个代码示例,展示了这些事情的成效:
class A
{
public:
virtual void foo() {printf("foo !");};
};
class B
{
public:
virtual void bar() {printf("bar !");};
};
...
A* a = new A();
((B*)a)->bar();
显然我可以通过拨打B-&gt;栏来拨打A foo,B甚至没有A !!!!魔法 ?没有。恰好B-> bar具有与A-> foo相同的地址。考虑到您的示例,A的析构函数与B的析构函数具有相同的地址。
关于您的评论,如果这对图书馆开发PoV是安全的:
如果开发人员不知道正确的投射方式,那不是你的问题,或者如果开发人员真的想打破你的库,他会的。你的工作是在正确使用东西时提供工作代码。如果库的用户想要从库中重新解释强制转换对象或者使用其他非标准的,未定义的行为,那么你就无法做任何事情(例如,一些随机的家伙想要使用malloc分配对象并不是你的错...有趣的交易与那个家伙!)。