一个非常简单的C ++代码:
#include <iostream>
using namespace std;
class Foo {
public:
void callPrint() {
print();
}
void print() {
cout << "Foo" << endl;
}
};
class Bar : public Foo {
public:
void print() {
cout << "Bar" << endl;
}
};
int main() {
Bar b;
b.callPrint();
return 0;
}
这里的输出是&#34; Foo&#34;。如果我制作&#34; Foo :: print()&#34;虚拟,输出将是&#34; Bar&#34;。我的问题是:
当Foo::print()
是非虚拟的时,为什么在将Bar
对象传递给Foo::callPrint()
时调用它,是否存在类型(静态和动态)不匹配?
当Foo:callPrint()
为虚拟时,调用b.callPrint()
不是通过引用或指针,而是调用Bar::print()
。这不是所谓的多态,那么如何根据语言定义或编译器实现来解释这种行为?
答案 0 :(得分:13)
当您调用b.callPrint();
时,控件将转移到基类中的函数callPrint
。现在,this
的类型为Foo *
,指向Bar *
的对象。现在,当您致电print()
或this->print()
如果是非虚函数,则在编译时根据this
的类型决定被调用函数,从而调用Foo::print
。
在虚函数的情况下,被调用函数在运行时根据指向对象的类型决定,因此调用Bar::print
。
你想增加更多乐趣吗?将函数Foo::print()
设为virtual
函数,并从Foo
的构造函数中调用它,并创建Bar
的对象。
答案 1 :(得分:7)
标准有很好的段落(10.3 / 9):
[注意:虚函数调用的解释取决于它所对象的类型 调用(动态类型),而非虚拟成员函数的调用的解释取决于 仅表示该对象的指针或引用的类型(静态类型)(5.2.2)。 - 结束说明]
print()
在隐式this
上调用,其(取消引用时)动态类型为Bar
,但在callPrint()
内,其静态类型为{{1} }。
答案 2 :(得分:1)
当它是非虚拟的时,子类不会覆盖对print
的调用,因此会打印“Foo”。
当它是虚拟的时,子类会覆盖对print的调用,从而打印出“Bar”。
这是预期的行为。当您将方法声明为虚拟时,您会说该类的行为取决于其子类并且可以(必须)被覆盖。在不知道所有子类的情况下,您无法理解虚拟类的行为。