有人给了我以下代码,并询问它打印了什么:
#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
您的困惑似乎是您期望在非虚函数上进行虚拟调度。您在指向
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
不是虚拟的。