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】:

&amp;objChild*Parent1* 的第一次显式转换是向上转换。结果将指向基类子对象。下一个显式转换是从Parent1*Parent2*。由于这些类没有直接关系,因此这是一个重新解释。但是类型不是指针互转换的,所以当你通过重新解释的指针调用函数时,程序的行为是不确定的。

你应该避免使用 C 风格的强制转换来防止这样的错误。在这种情况下,根本不需要显式转换。这可以正常工作:

Parent2 * p2 = &obj;

除非您知道指针的含义并且可以这样做,否则永远不要重新解释指针。

【讨论】:

你也可以提到Parent1* p1 = &amp;obj; Parent2* p2 = dynamic_cast&lt;Parent2*&gt;(p1); 也可以,我相信。 @N.Shead 这也可以。尽管如此,必须始终检查动态转换是否返回空指针或有效指针。 确实如此。 (或者当然是动态转换引用类型,它会抛出。)我只是怀疑,考虑到多重继承,这更有可能是 OP 最初试图做的事情。 @N.Shead 可能是。但是 OP 没有解释他们想要做什么以及为什么,所以我们不知道。

以上是关于C++意外调用继承类的函数的主要内容,如果未能解决你的问题,请参考以下文章

C++ 类的继承三(继承中的构造与析构)

在 C++ 继承中,当指向基类的指针对象指向派生类时,不调用派生类析构函数

C++中,继承时,创建子类对象,能否在子类构造函数初始化列表里调用基类构造函数?

C++中如何在子类的构造函数中调用基类的构造函数来初始化基类成员变量

C++ ——虚继承时的构造函数

C++ ——虚继承时的构造函数