试图理解为什么在使用 virtual 关键字和 vtables 时可能出现以下打印序列

问题描述 投票:0回答:1

有人给了我以下代码,并询问它打印了什么:

#include <iostream>
using namespace std;

class C;
class B;

class A {
private:
    B* pointerB;
    C* pointerC;
public:
    A(){ cout << "1"<< endl; }
    A(C* c1): pointerC(c1){ cout << "2"<< endl; }
    A(const A& a): pointerC(a.pointerC){ cout << "3"<< endl; }
    virtual void f() { cout << "4"<< endl; }
    void g() { print(); cout<< "5"<< endl; }
    virtual void h(){ print(); cout<< "6"<< endl; }
    virtual ~A(){ cout << "7"<< endl; }
    virtual void print() { cout << "8"<< endl; }
};

class B: public A {
private:
    int x;
public:
    B(int x1 = 0): x(x1){ cout << "9"<< endl; }
    B(const A& a) : A(a), x(2) { cout << "10"<< endl; }
    B(const B& b): A(b), x(2) { cout << "11"<< endl; }
    virtual void g() { x++; print();}
    void f(){ B::print(); cout << "12"<< endl; }
    void print() { cout << "13"<< x << endl; }
    virtual ~B(){ cout << "14"<< endl; }
};

class C: public B {
private:
    B b;
    A a;
public:
    C(): B(2){ cout << "15"<< endl; }
    C(B& b) : b(b){ cout << "16"<< endl; }
    C (const C &c): B(c){ cout << "17"<< endl; }
    void f(){ cout << "18"<< endl; }
    void h(B b) {  cout << "19"<< endl; }
    void print() { cout << "20"<< endl; A:: print(); }
    ~C(){ cout << "21"<< endl; }
};

int main() {
    A* ptrAtoB = new B;
    B* ptrBtoC = new C;
    A* ptrAtoC = new C;
    cout << "-------------------" << endl;
    ptrAtoB->f();
    ptrAtoB->g();
}

第一行打印:1 9 1 9 1 9 1 15 1 9 1 9 1 15,我明白为什么了。 它的第二部分让我感到困惑。 对于

ptrAtoB->f();
,我们转到 B 类并执行 B::f() 函数,该函数使用 B::print() 打印 13,然后 x=0,然后 B::f() 打印 12。 然而,下一行,我希望
ptrAtoB->g();
做同样的事情,意思是使用 B 类函数打印 13 1 因为我们使用 B::g() 将 x 提高到 1,然后打印。 最终发生的事情是,我们首先转到 A::g(),然后以某种方式使用 B::print() 打印 13 0,然后返回到 A::g() 打印 5。 这是为什么?

控制台的最终输出是:

1
9
1
9
1
9
1
15
1
9
1
9
1
15
-------------------
130
12
130
5
c++ virtual
1个回答
1
投票

您的困惑似乎是您期望在非虚函数上进行虚拟调度。您在指向

g
的指针上调用
A
A::g
不是虚拟的,因此
A::g
被调用。
B::g
被声明为虚拟的事实不会改变
A::g
不是虚拟的事实。它也不会改变您通过指向
g
的指针调用
A
的事实。

一个更简单的例子,只减少了似乎引起你困惑的细节:

#include <iostream>

struct A {
    void foo() const {std::cout << "A\n";}
};

struct B : A {
    virtual void foo() const { std::cout << "B\n";}
};

void bar(const A& a) {
    a.foo();
}

int main() {
    bar(A{});
    bar(B{});
}

试试看。调用

bar
永远不会打印出
A
以外的东西,因为
A::foo
不是虚拟的。

© www.soinside.com 2019 - 2024. All rights reserved.