#include <iostream>
using namespace std;
class A {
public:
void m1(){ cout << 'A'; }
virtual void m2(){ cout << 'B'; }
virtual void m3(){ cout << 'C'; }
};
class B: public A {
public:
void m1(){ cout << 'D'; }
void m2(){ cout << 'E'; }
};
class C: public B {
public:
void m3(){ cout << 'F'; }
};
int main()
{
cout << "Hello World!" << endl;
A* a = new B();
a->m1();
a->m2();
a->m3();
return 0;
}
输出是什么?我最初认为它将是“D E C”,但在运行程序后它是“A E C”
可以详细说明这行代码背后的内容:
A* a = new B();
答案 0 :(得分:6)
根据对象的动态(运行时)类型调度虚拟成员函数。根据对象的 static (编译时)类型调度非虚拟成员函数。
A *a = new B();
a
指向动态类型为B
的对象。然而,a
的静态类型为A*
,这意味着*a
的静态类型为A
。
根据动态类型调度虚拟函数(m2
和m3
),因此调用B::m2
和B::m3
。
根据静态类型调度非虚函数。 *a
的静态类型为A
,因此调用A::m1
。
new
行究竟发生了什么?类型为B
的新对象是动态创建的,new
表达式返回指向该对象的指针(类型为B*
)。然后,对该指针应用派生到基础的转换,将其转换为A*
,用于初始化变量a
。
在伪代码中,显示中间步骤:
B *tmp_b = new B(); // allocate and initialise B object
A *tmp_a = convert_derived_to_base(tmp_b);
A *a = tmp_a;
答案 1 :(得分:1)
m1方法在A类中不是虚拟的,它不能被覆盖.m2是虚拟的,所以它用B类方法覆盖。
答案 2 :(得分:1)
输出
AEC
原因是A::m1
未声明virtual
。在这一行
A* a = new B();
您正在声明名为A*
的{{1}}变量,该变量实际上是派生类a
的一个实例。这是允许的,因为“B
是一种B
”。
当函数声明为A
时,如果派生类定义了该函数,那么基类中的函数将被派生类中的版本覆盖。因此,将进行以下调用
virtual
答案 3 :(得分:0)
此处Class A
是您的父类,因此要覆盖父类的方法,您需要在A类中将其设为virtual
。以便Class B
&#39; s方法将被调用。请参阅Virtual Functions
答案 4 :(得分:0)
void m1(){ cout << 'A'; }
virtual void m2(){ cout << 'B'; }
virtual void m3(){ cout << 'C'; }
根据您的程序代码,输出完全正常。
void m1(){ cout << 'A';
不是虚函数。
因此,a->m1();
会调用m1
的基本版本,并将o / p称为A
。
m2()
是一个虚函数,它在B类中有一个新的实现。
void m2(){ cout << 'E'; }
因此a->m2();
调用class B
函数的m2
版本并输出E
。
m3
内没有class B
的新实现。
因此a->m3();
调用从m3
继承的class A
。
要将o / p设为DEC
,您只需将m1
函数更改为虚拟函数,如下所示
class A {
public:
virtual void m1(){ cout << 'A'; }
virtual void m2(){ cout << 'B'; }
virtual void m3(){ cout << 'C'; }
};