我在虚函数和参考中有一个问题。当我尝试准备面试时,这是一个难题。我谷歌一段时间,但看不到确切的情况。
代码如下:
class A{
public:
virtual void foo() {cout << "A::foo" << endl;}
};
class B: public A{
public:
void foo() {cout << "B::foo" << endl;}
};
class C: public B{
public:
void foo() {cout << "C::foo" << endl;}
};
int main(void){
C c;
B *q;
q = &c; q->foo();
return 0;
}
我对输出的想法是B :: foo,但答案实际上是C :: foo。有人能告诉我为什么vtable不会选择B的实现吗?感谢
答案 0 :(得分:2)
foo
在B
中是虚拟的,因为它会覆盖基类中的虚函数,即使它未显式声明为virtual
。
通过q->foo()
调用的对象的派生类型最多的是C
和C
foo
的最终覆盖,其签名为void foo()
C::foo
1}}所以这是被调用的函数。
答案 1 :(得分:2)
如果foo
不虚拟,则调用的函数将基于指针的类型,并且将调用B::foo()
。
由于foo
在基类中定义为虚拟,因此它在所有派生类中保持虚拟。在这种情况下,被调用的函数基于指向的对象类型,而不是指针的类型。由于指向的对象是C
,因此被调用的函数是C::foo()
。
答案 2 :(得分:1)
因为q
指向C
对象,并且其虚函数表包含虚函数foo
。请记住,在类中声明的任何虚函数在任何派生类中都是虚函数。这是使用基类访问派生类的方法。
答案 3 :(得分:0)
AFAIK:
一旦使用了vtable - 在这种情况下强制virtual
A::foo
声明 - 你声明的类型并不重要,它总是调用最具体方法的方法 - 在这种情况下是C::foo
。
答案 4 :(得分:0)
有人能告诉我为什么vtable不会选择B的实现吗?
这是拥有虚函数的重点,因此通过基类指针调用overriden方法仍将从派生类调用该方法。
q
的类型为B *
,但它指向C
个对象。因此,当您调用虚函数foo()
时,将调用C::foo()
实现。
即使foo()
和virtual
中的B
未标记C
,它仍然是虚函数,因为它在A
中声明为此类。
如果您希望调用B::foo()
,则需要明确调用它。
q->B::foo();
答案 5 :(得分:0)
foo()
是一个虚函数,这意味着调用q
实例实际指向的类中定义的版本而不是在{{1}}中定义的版本。指针类型中的类。
请记住,一旦成员函数在类层次结构的某个地方被标记为虚拟,它就是虚拟的,即在B类和C类中不需要再将该函数显式标记为虚拟,因为这已经在A类中完成了。