我正在研究virtual
关键字在C ++中的效果,我想出了这段代码。
#include<iostream>
using namespace std;
class A {
public:
virtual void show(){
cout << "A \n";
}
};
class B : public A {
public:
void show(){
cout << "B \n";
}
};
class C : public B {
public:
void show(){
cout << "C \n";
}
};
int main(){
A *ab = new B;
A *ac = new C;
B *bc = new C;
ab->show();
ac->show();
bc->show();
}
预期输出为:
B
C
B
因为B中的show
函数是非虚拟的。但是编译它的结果是:
B
C
C
它表现为B中的show
函数是虚拟的。为什么会这样? B班在这里被覆盖了吗?如果我将C类指向B类,我怎么指向A类?
答案 0 :(得分:7)
如果在virtual
类中指定,则无需在派生类中将函数指定为base
。
答案 1 :(得分:7)
根据C ++ 2017标准(10.1.2函数说明符)
2虚拟说明符只能在初始声明中使用 非静态类成员函数;见13.3。
和(13.3虚拟功能)
2 如果在类Base和in中声明了虚拟成员函数vf 一个类派生,直接或间接来自Base,一个成员 函数vf,同名,参数类型列表(11.3.5), 与Base :: vf一样的cv-qualification和ref-qualifier(或不存在) 声明,然后Derived :: vf也是虚拟的(无论是否是这样 声明)并且它覆盖111 Base :: vf。为方便起见,我们这样说 任何虚函数都会覆盖自身。虚拟成员函数C :: vf 除非派生的类最多,否则类对象S是最终的覆盖 (4.5)其中S是基类子对象(如果有的话)声明或 继承覆盖vf的另一个成员函数。在派生中 class,如果基类子对象的虚拟成员函数有更多 超过一个最终的推翻,该计划是不正确的。
因此,类show
中的函数B
是一个虚函数,因为它与类A
中声明的函数具有相同的签名。
在课程B
中添加限定符const
到成员函数show
时,请考虑一个更有趣的示例。
#include<iostream>
using namespace std;
class A {
public:
virtual void show(){
cout << "A \n";
}
};
class B : public A {
public:
void show() const{
cout << "B \n";
}
};
class C : public B {
public:
void show() {
cout << "C \n";
}
};
int main(){
A *ab = new B;
A *ac = new C;
B *bc = new C;
ab->show();
ac->show();
bc->show();
}
在这种情况下,输出看起来像
A
C
B
在此表达式声明中
ab->show();
在类show
中声明了虚拟函数A
。
在本声明中
ac->show();
在类C
中调用了相同的虚函数。 compier使用类A中的虚函数声明,因为指针ac
的静态类型是A *
。
在本声明中
bc->show();
使用限定符show
调用非虚拟成员函数const
,因为指针bc
的静态类型是B *
,并且编译器在隐藏在类B
中声明的虚函数的类A
。
对于原始程序,您可以使用说明符override
使类定义更清晰。例如
#include<iostream>
using namespace std;
class A {
public:
virtual void show(){
cout << "A \n";
}
};
class B : public A {
public:
void show() override{
cout << "B \n";
}
};
class C : public B {
public:
void show() override{
cout << "C \n";
}
};
int main(){
A *ab = new B;
A *ac = new C;
B *bc = new C;
ab->show();
ac->show();
bc->show();
}
答案 2 :(得分:0)
行为是正确的。由于show
函数是虚拟的,因此调用的版本将是附加到您调用它的实例的版本,而不是由该实例的类型描述的版本(可以是该实例的基础)实例的真实类型。)