子类中未调用 C++ 虚函数

标签 c++ polymorphism virtual-functions

考虑这个简单的情况:

A.h

class A {
public:
    virtual void a() = 0;
};

B.h

#include <iostream>

class B {
public:
    virtual void b() {std::cout << "b()." << std::endl;};
};

C.h

#include "A.h"
#include "B.h"

class C : public B, public A {
public:
    void a() {std::cout << "a() in C." << std::endl;};
};

int main() {
    B* b = new C();
    ((A*) b)->a();    // Output: b().

    A* a = new C();
    a->a();           // Output:: a() in C.

   return 0;
}

换句话说:
- A是一个纯虚类。
- B 是一个没有父类(super class)和一个非纯虚函数的类。
- C 是 A 和 B 的子类,并且覆盖了 A 的纯虚函数。

让我吃惊的是第一个输出即

((A*) b)->a();    // Output: b().

虽然我在代码中调用了a(),但是调用了b()。我的猜测是,这与变量 b 是指向类 B 的指针这一事实有关,它不是类 A 的子类。但运行时类型仍然是指向 C 实例的指针。

从 Java 的角度来看,解释这个奇怪行为的确切 C++ 规则是什么?

最佳答案

您正在无条件转换 bA*使用 C 风格的转换。编译器不会阻止你这样做;你说这是一个A*所以这是一个 A* .所以它将它指向的内存视为 A 的一个实例。 .自 a()A 中列出的第一个方法的 vtable 和 b()B 中列出的第一个方法的 vtable,当你调用 a() 时在一个真正是 B 的对象上, 你得到 b() .

你很幸运,对象布局是相似的。不能保证一定是这种情况。

首先,您不应该使用 C 风格的转换。你应该使用 C++ casting operators哪个更安全(尽管您仍然可以搬起石头砸自己的脚,所以请仔细阅读文档)。

其次,你不应该依赖这种行为,除非你使用 dynamic_cast<> .

关于子类中未调用 C++ 虚函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2105282/

相关文章:

c++ - 使用共享库的后果是打开另一个具有不同构建类型的共享库

android - 在Android中,如何在jni_onLoad方法中加载其他共享库?

C++虚拟模板函数

c++ - 覆盖虚函数和隐藏非虚函数有什么区别?

c++ - 使用范围解析运算符时在构造函数中调用虚方法是否安全?

c++ - ostream .open 函数不存在 (C++)

c++ - for循环的每次迭代都添加一个新语句。二维数组排队

C++ 多态性。为什么这是有效的?

C#继承问题

c++ - 实现后期多态性的最佳方式