与 C++ 中的 virtual 关键字混淆

Confusion with virtual keyword in C++

我正在研究 C++ 中 virtual 关键字的效果,我想出了这段代码。

#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

因为 show B 中的函数是非虚拟的。但是编译时的结果是:

B
C
C

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

如果在 base class.

中指定函数,则无需在派生 class 中将函数指定为 virtual

行为是正确的。由于 show 函数是虚拟的,因此调用的版本将是附加到您正在调用它的实例的版本,而不是该实例类型所描述的版本(它可以是该实例的真实版本的基础类型)。

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

2 The virtual specifier shall be used only in the initial declaration of a non-static class member function; see 13.3.

和(13.3虚函数)

2 If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (11.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides111 Base::vf. For convenience we say that any virtual function overrides itself. A virtual member function C::vf of a class object S is a final overrider unless the most derived class (4.5) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf. In a derived class, if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed.

因此 class B 中的函数 show 是虚函数,因为它与 class [=18= 中声明的函数具有相同的签名].

考虑一个更有趣的例子,在 class B 中,向成员函数 show.

添加限定符 const
#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();

在classA中声明了虚函数show

在此声明中

    ac->show();

调用了在 class C 中覆盖的相同虚函数。编译器使用class A中的虚函数声明,因为指针ac的静态类型是A *.

在此声明中

    bc->show();

调用非虚成员函数show,限定符const,因为指针bc的静态类型是B *,编译器找到函数在 class B 中隐藏了在 class A..

中声明的虚函数

对于原始程序,您可以使用说明符 override 使 class 定义更加清晰。例如

#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();

}