假设我们有以下代码:
#include <iostream>
#include <string>
using namespace std;
class A {
public:
A() : m_name("A Name") {}
virtual void printName() { cout << m_name << "\n"; }
private:
string m_name;
};
class B : public A {
public:
B() : b_m_name("B Name") {}
void printName() { cout << b_m_name << "\n"; }
private:
string b_m_name;
};
int main() {
A* ONE = new B;
B* TWO = new B;
ONE->printName();
TWO->printName();
return 0;
}
编辑:我的问题不是“输出是什么”;我知道我可以在 visual studio 中运行它并得到答案。我的问题更多是关于“为什么输出是这样的?”
我猜它会先输出“A Name”,然后再输出“B name”。我对此的一些推理尝试是 ONE 是类型 A 的指针,因此指向新 B 对象的一部分,即 A 对象。因此,当我们调用 ONE.printName();它调用类 A 的 printName(),反之亦然。
我不确定我的推理(甚至我的回答)是否正确。这有点令人困惑,因为我知道编译器可以有效地在 A* 和 B* 类型的指针之间进行转换,所以它们是一回事…… 这特别让我感到困惑,因为如果我的上述推理是正确的(ONE 是 A 类型的指针,因此指向新 B 的 A 部分),那么不能说它同时指向新 B 和A 在 B 中,因为它们实际上位于同一地址?如果是这样,为什么编译器不同时调用 A 和 B 的 printName() 函数? 区别是否仅在于我们宣布 ONE 为 A* 而不是 B*?
任何澄清将不胜感激。
我的猜测是它会先输出“A Name”,然后再输出“B name”。我对此的一些推理尝试是 ONE 是一个指针 属于 A 类型,因此指向新 B 对象的 A 部分 目的。因此,当我们调用 ONE.printName();它称为A类 printName(),反之亦然。
根据用于调用虚函数的指针的动态类型调用虚函数。
来自 C++ 17 标准(3 个术语和定义)
3.9
动感型
最派生对象(4.5)的类型,其 glvalue 引用 [示例:如果指针 (11.3.1) p 的静态类型为“pointer 到 B 类”指向 D 类的对象,派生自 B (第 13 条),表达式 *p 的动态类型是“D”。参考 (11.3.2) 的处理方式类似。 - 结束示例]
你声明了两个指向分配对象的指针
class B
A* ONE = new B;
B* TWO = new B;
指针
ONE
的静态类型是A *
,动态类型是B *
。
所以对于这个说法
ONE->printName();
函数
printName
在类A
中搜索。因为它是一个虚函数并且指针的动态类型是B *
然后在指针指向的类型B
的对象中的虚函数指针表中搜索指向该函数的指针ONE
, 所以类中定义的函数B
被调用了
在这份声明中
TWO->printName();
因为指针
TWO
的静态类型是B *
然后在类B
中搜索函数。由于指针的动态类型也是B *
然后调用类B
中定义的函数。
在这两个语句中调用了类
B
中定义的相同函数。
所以两个语句输出
B Name
就是虚函数的概念。