用C ++进行反直觉函数调用

时间:2016-06-16 05:51:42

标签: c++

一个非常简单的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;。我的问题是:

  1. Foo::print()是非虚拟的时,为什么在将Bar对象传递给Foo::callPrint()时调用它,是否存在类型(静态和动态)不匹配?

  2. Foo:callPrint()为虚拟时,调用b.callPrint()不是通过引用或指针,而是调用Bar::print()。这不是所谓的多态,那么如何根据语言定义或编译器实现来解释这种行为?

3 个答案:

答案 0 :(得分:13)

当您调用b.callPrint();时,控件将转移到基类中的函数callPrint。现在,this的类型为Foo *,指向Bar *的对象。现在,当您致电print()this->print()

  1. 如果是非虚函数,则在编译时根据this的类型决定被调用函数,从而调用Foo::print

  2. 在虚函数的情况下,被调用函数在运行时根据指向对象的类型决定,因此调用Bar::print

  3. 你想增加更多乐趣吗?将函数Foo::print()设为virtual函数,并从Foo的构造函数中调用它,并创建Bar的对象。

答案 1 :(得分:7)

标准有很好的段落(10.3 / 9):

  

[注意:虚函数调用的解释取决于它所对象的类型   调用(动态类型),而非虚拟成员函数的调用的解释取决于   仅表示该对象的指针或引用的类型(静态类型)(5.2.2)。 - 结束说明]

print()在隐式this上调用,其(取消引用时)动态类型为Bar,但在callPrint()内,其静态类型为{{1} }。

答案 2 :(得分:1)

  1. 当它是非虚拟的时,子类不会覆盖对print的调用,因此会打印“Foo”。

  2. 当它是虚拟的时,子类会覆盖对print的调用,从而打印出“Bar”。

  3. 这是预期的行为。当您将方法声明为虚拟时,您会说该类的行为取决于其子类并且可以(必须)被覆盖。在不知道所有子类的情况下,您无法理解虚拟类的行为。