与C ++中的虚拟关键字混淆

时间:2017-11-09 12:14:08

标签: c++ function c++11 inheritance virtual

我正在研究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类?

3 个答案:

答案 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函数是虚拟的,因此调用的版本将是附加到您调用它的实例的版本,而不是由该实例的类型描述的版本(可以是该实例的基础)实例的真实类型。)