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

Hel*_*ter 5 c++ virtual inheritance function c++11

我正在研究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();

}
Run Code Online (Sandbox Code Playgroud)

预期的产出是:

B
C
B
Run Code Online (Sandbox Code Playgroud)

因为showB中的函数是非虚拟的.但是编译它的结果是:

B
C
C
Run Code Online (Sandbox Code Playgroud)

它的行为就像showB中的函数是虚拟的一样.为什么会这样?B班在这里被覆盖了吗?如果我将C类指向B类,我怎么指向A类?

Gau*_*gal 7

virtual如果在base类中指定,则不需要在派生类中指定函数.

  • @Helicopter不,虚拟方法不能在派生类中成为非虚拟方法.但是,您可以使用`final`说明符阻止覆盖虚方法. (2认同)

Vla*_*cow 7

根据C++ 2017标准(10.1.2函数说明符)

2虚拟说明符只能用于非静态类成员函数的初始声明; 见13.3.

和(13.3虚拟功能)

2 如果虚拟成员函数vf在类Base和Derived类中声明,直接或间接从Base派生,则成员函数vf具有相同的名称,参数类型列表(11.3.5),cv-qualification,声明了Base :: vf的ref-qualifier(或不存在相同的),然后Derived :: vf也是虚拟的(无论是否如此声明)并覆盖111 Base :: vf.为方便起见,我们说任何虚函数都会覆盖自身.类对象S的虚拟成员函数C :: vf是最终覆盖,除非其中S是基类子对象(如果有)的最派生类(4.5)声明或继承覆盖vf的另一个成员函数.在派生类,如果一个基类子对象的虚拟成员函数具有一个以上的最终超控器程序是非法的构造.

因此,showB中的函数是虚函数,因为它具有与类中声明的函数相同的签名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();

}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,输出看起来像

A 
C 
B 
Run Code Online (Sandbox Code Playgroud)

在这个表达式声明中

    ab->show();
Run Code Online (Sandbox Code Playgroud)

有一种叫做show类中声明的虚函数A.

在这个声明中

    ac->show();
Run Code Online (Sandbox Code Playgroud)

在类中重写了相同的虚函数C.compier使用类A中的虚函数声明,因为指针的静态类型acA *.

在这个声明中

    bc->show();
Run Code Online (Sandbox Code Playgroud)

show使用限定符调用非虚成员函数,const因为指针的静态类型bcB *,并且编译器在类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();

}
Run Code Online (Sandbox Code Playgroud)