下面是一些代码,用于显示重写虚拟方法的时间。它输出: 乙 乙 一个 一个 乙 一个 它是否正确?我认为bar方法不能被覆盖......?
#include <iostream>
using namespace std;
class A
{
public:
virtual void foo(){cout<<"A"<<endl;}
void bar(){cout<<"A"<<endl;}
};
class B : public A
{
public:
void foo(){cout<<"B"<<endl;}
void bar(){cout<<"B"<<endl;}
};
int main()
{
B b;
A * pA = new A;
A * pA2 = &b;
b.foo(); b.bar();
pA->foo(); pA->bar();
pA2->foo(); pA2->bar();
}
答案 0 :(得分:2)
我没有看到任何错误:
B b;
b.foo(); b.bar();
您声明并初始化B
的实例,编译类型为B
,运行时类型为B
。不需要多态性(因为没有涉及指针,所以也无法实现)。
A * pA = new A;
pA->foo(); pA->bar();
您声明指向A
的指针,并使用A
的实例对其进行初始化。即使在这种情况下没有必要,多态性仍然有效,因此调用来自foo()
的{{1}}和bar()
。
A
您声明指向A * pA2 = &b;
pA2->foo(); pA2->bar();
的指针,并使用对A
的引用对其进行初始化。编译时间类型为B
,运行时类型为A*
。应用通过虚函数的多态性,因此虚拟方法为B*
,而非虚拟方法为B::foo()
答案 1 :(得分:1)
b.foo()
提供B
,
b.bar()
也会B
隐藏A::bar()
。它不是压倒性的,它隐藏着名字。
pA->foo()
提供A
,pA->bar()
提供A
,
pA2->foo()
提供B
,因为它是虚函数。
pA2->bar()
给出A
,因为它不是虚函数。它是静态链接的,并调用A::bar()
。
答案 2 :(得分:1)
前两个输出应该都是B,因为你在类型B的对象上调用foo()和bar()。因为你没有使用指针,编译器知道它是B类型的对象,因此不需要查阅vtable来调用方法,所以即使bar()不是虚拟的,编译器也知道使用B实现。
接下来的两个输出都应该是A,因为你在指向类型A的对象的指针上调用foo()和bar()。在这种情况下,foo()是虚拟的,而vtable指向该方法的实现。 bar()不是虚拟的,因此编译器决定使用A实现。
最后两个输出应该是B和A,因为你在指向类型B的对象的指针上调用foo()和bar()。在这种情况下,foo()是虚拟的,而vtable指向方法的B实现。 bar()不是虚拟的,因此编译器决定使用A实现,因为您正在使用指向A类对象的指针。
答案 3 :(得分:0)
这是正确的,不会覆盖pA2-&gt; bar()调用。即使它是一个B对象,也可以将它转换为A,编译器调用A类的成员函数。
foo()是虚拟的,因此包含在类B中的是指向哪个版本的foo()对于类是正确的指针,无论它被转换到何处。
此包含称为指向虚函数表的指针。只要您的类具有虚拟成员,就会为其创建一个静态函数表(并且还将包括任何其他后续虚函数),另外一个常量隐藏成员指针指向该表。当您转换对象时,函数表不会更改,任何虚函数都将保持“附加”到原始类型。
PS,别忘了删除pA ...你目前有内存泄漏:)