C++意外调用继承类的函数
Posted
技术标签:
【中文标题】C++意外调用继承类的函数【英文标题】:C++ unexpected calling of function of inherited classes 【发布时间】:2020-01-08 21:57:55 【问题描述】:我做了以下 3 个课程:
struct Parent1
virtual void f()
cout << "\nParent1::f";
;
struct Parent2
virtual void g()
cout << "\nParent2::g";
virtual void z()
cout << "\nParent2::z";
;
struct Child : public Parent1, public Parent2
virtual void h()
cout << "\nChild::h";
;
在 main 中,当我调用 Parent2
的函数 z
时,它改为调用子类的函数 h
。为什么会这样?
以下是main
函数:
int main()
Child obj;
Parent2 * p2 = (Parent2*)(Parent1*)&obj;
p2->z();
return 0;
【问题讨论】:
您正在调用未定义的行为,因为您无法从Parent1*
转换为 Parent2*
,只需摆脱 (Parent1*)
。 (实际上你不需要任何演员,这是隐式完成的)。
@n314159 我真的很想知道为什么会这样?
事实上,在这种情况下,我相信dynamic_cast
会正常工作并做你想做的事。
@Paul 对于这样的上调,static_cast
绰绰有余(甚至会为这种错误抛出一个很好的错误!ideone.com/cNKWUc)
@AqleemaSajid 之所以发生这种情况,是因为您使用了不安全的 C 风格转换,在这种情况下会进行不正确的对话并且不会警告您。这也是推荐使用适当的 C++ 强制转换的主要原因之一。
【参考方案1】:
从&obj
即Child*
到Parent1*
的第一次显式转换是向上转换。结果将指向基类子对象。下一个显式转换是从Parent1*
到Parent2*
。由于这些类没有直接关系,因此这是一个重新解释。但是类型不是指针互转换的,所以当你通过重新解释的指针调用函数时,程序的行为是不确定的。
你应该避免使用 C 风格的强制转换来防止这样的错误。在这种情况下,根本不需要显式转换。这可以正常工作:
Parent2 * p2 = &obj;
除非您知道指针的含义并且可以这样做,否则永远不要重新解释指针。
【讨论】:
你也可以提到Parent1* p1 = &obj; Parent2* p2 = dynamic_cast<Parent2*>(p1);
也可以,我相信。
@N.Shead 这也可以。尽管如此,必须始终检查动态转换是否返回空指针或有效指针。
确实如此。 (或者当然是动态转换引用类型,它会抛出。)我只是怀疑,考虑到多重继承,这更有可能是 OP 最初试图做的事情。
@N.Shead 可能是。但是 OP 没有解释他们想要做什么以及为什么,所以我们不知道。以上是关于C++意外调用继承类的函数的主要内容,如果未能解决你的问题,请参考以下文章
在 C++ 继承中,当指向基类的指针对象指向派生类时,不调用派生类析构函数
C++中,继承时,创建子类对象,能否在子类构造函数初始化列表里调用基类构造函数?