c++ 尝试理解为什么在使用虚拟关键字和vtables时可以执行以下打印序列

bwntbbo3  于 2023-03-25  发布在  其他
关注(0)|答案(1)|浏览(111)

我得到了下面的代码,并问它打印什么:

#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; }
};

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

对于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。为什么?
控制台上的最终输出为:

130
12
130
5
but5z9lq

but5z9lq1#

你的困惑似乎是你期望在一个非虚函数上进行虚分派。你在一个指向A的指针上调用gA::g不是虚的,B::g被声明为virtual的事实并不改变A::g不是virtual的事实。它也不会改变您通过指向A的指针调用g的事实。
一个简单得多的例子,只简化到似乎会引起你混淆的细节:

#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不是虚拟的。

相关问题