我对基类析构函数中的 this 指针有一个奇怪的问题。
问题描述:
我有 3 个课程:A1,A2,A3
A2从A1公开继承,从A3私下继承
class A2:private A3, public A1 {...}
A3有一个函数getPrimaryInstance() ...返回A1对A2实例的类型引用:
A1& A3::getPrimaryInstance()const{
static A2 primary;
return primary;
}
A3构造函数如下所示:
A3(){
getPrimaryInstance().regInst(this);
}
(其中regInst(...)是A1中定义的函数,用于存储指向所有A3实例的指针)
同样的A3析构函数:
~A3(){
getPrimaryInstance().unregInst(this);
}
^这里是问题发生的地方!
当名为primary的静态A2实例在程序终止时被销毁时,将调用A3析构函数,但在~A3内部,我尝试访问与我正在销毁的实例相同的函数。 =>运行时访问冲突!
所以我认为可以用一个简单的 if 语句来修复,如下所示:
~A3(){
if(this != (A3*)(A2*)&getPrimaryInstance()) //Original verison
//if (this != dynamic_cast<A3*>(static_cast<A2*>(&getPrimaryInstance())))
//Not working. Problem with seeing definitions, see comments below this post
getPrimaryInstance().unregInst(this);
}
(双重演员的原因是继承:)
A1 A3
。\ /
. A2
(但这并不重要,可能只是(int) -casted 或其他)
更重要的是它仍然崩溃。使用调试器单步执行代码会发现,当我的A2 主实例被破坏时,析构函数中的this指针和我通过调用getPrimaryInstance()获得的地址由于某种原因根本不匹配!我不明白为什么this指针指向的地址总是不同于它(据我所知)应该是的地址。:(
在析构函数中这样做:
int test = (int)this - (int)&getPrimaryInstance();
还向我展示了差异不是恒定的(我曾短暂地认为存在一些恒定偏移),所以当它应该是同一个时,它就像是两个完全不同的对象。:(
我正在使用 VC++ Express (2008) 进行编码。在谷歌搜索了一下之后,我发现了以下 MS 文章:
修复:“this”指针在基类的析构函数中不正确
这与我遇到的问题不同(据说它在 C++.Net 2003 中也已修复)。但不管这些症状看起来很相似,而且它们确实提供了一个简单的解决方法,所以我决定尝试一下:
删除了 not-working- if -statement 并在A2的第二个继承之前添加了virtual,如下所示:
class A2:private A3, public A1 {...} // <-- old version
class A2:private A3, virtual public A1 {...} //new, with virtual!
它奏效了!this指针看起来仍然是错误的,但不再给出访问冲突。
所以我最大的问题是为什么?
为什么this指针不指向它应该指向的位置(?)?
为什么像上面那样向继承添加virtual可以解决它(尽管它仍然指向&getPrimaryInstance()以外的其他地方)?
这是一个错误吗?有人可以在非 MS 环境中尝试吗?
最重要的是:这安全吗?当然它不再抱怨了,但我仍然担心它没有做它应该做的事情。:S
如果有人对此有知识或经验并且可以帮助我理解它,我将非常感激,因为我仍在学习 C++,这完全超出了我目前的知识范围。