简体   繁体   English

用C ++反直觉函数调用

[英]A counter-intuitive function call in C++

A quite simple C++ code: 一个非常简单的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;
}

Here the output is "Foo". 这里的输出是“Foo”。 And if I make the "Foo::print()" virtual, the output will be "Bar". 如果我将“Foo :: print()”设为虚拟,则输出将为“Bar”。 My questions are: 我的问题是:

  1. When the Foo::print() is non-virtual, why is it called when a Bar object is passed to Foo::callPrint() , is there type (both static and dynamic) mismatch? Foo::print()是非虚拟的时,为什么在将Bar对象传递给Foo::callPrint()时调用它,是否存在类型(静态和动态)不匹配?

  2. When Foo:callPrint() is virtual, the call b.callPrint() is not via reference or pointer, however Bar::print() is called. Foo:callPrint()是虚拟的时,调用b.callPrint()不是通过引用或指针,而是调用Bar::print() This is not so-called polymorphism, then how to explain this behavior, according to either language definition or compiler implementation? 这不是所谓的多态,那么如何根据语言定义或编译器实现来解释这种行为?

When you call b.callPrint(); 当你调用b.callPrint(); , control transfers to function callPrint in base class. ,控制转移到基类中的函数callPrint Now the type of this is Foo * which points to an object of Bar * . 现在的类型thisFoo * ,它指向的对象Bar * Now when you call print() or this->print() 现在当你调用print()this->print()

  1. In case of non virtual function, the called function is decided at compile time on basis of type of this and thus Foo::print is invoked. 在非虚拟功能的情况下,被调用的函数是在编译时决定类型的基础this ,因此Foo::print被调用。

  2. In case of virtual function, the called function is decided at run times based on the type of pointed object, and thus Bar::print is invoked. 在虚函数的情况下,基于指向对象的类型在运行时决定被调用函数,因此调用Bar::print


Do you want to add more fun? 你想增加更多乐趣吗? Make the function Foo::print() a virtual function and call it from the constructor of Foo and create an object of Bar . 使函数Foo::print()成为一个virtual函数,并从Foo的构造函数中调用它并创建一个Bar对象。

Standard has nice paragraph (10.3/9): 标准有很好的段落(10.3 / 9):

[ Note: The interpretation of the call of a virtual function depends on the type of the object for which it is called (the dynamic type), whereas the interpretation of a call of a non-virtual member function depends only on the type of the pointer or reference denoting that object (the static type) (5.2.2). [注意:虚函数调用的解释取决于调用它的对象的类型(动态类型),而非虚函数函数调用的解释仅取决于它的类型。表示该对象的指针或引用(静态类型)(5.2.2)。 — end note ] - 结束说明]

print() is called on implicit this whose (when dereferenced) dynamic type is Bar , however inside callPrint() it's static type is Foo . print()被调用隐this ,其(提领时)动态类型是Bar ,但是里面callPrint()它的静态类型是Foo

  1. When it is non virtual the call to print is not overridden by the subclass and thus prints "Foo". 当它是非虚拟的时,子类不会覆盖对print的调用,因此打印“Foo”。

  2. When it is virtual the call to print is overridden by the subclass and thus the prints "Bar". 当它是虚拟的时,子类会覆盖对print的调用,从而打印出“Bar”。

This is expected behaviour. 这是预期的行为。 When you declare a method as virtual then you are saying that the behaviour of the class depends on its subclasses and can (has to) be overridden. 当您将方法声明为虚拟时,您会说该类的行为取决于其子类并且可以(必须)被覆盖。 You cannot understand the behaviour of a virtual class without knowing all its subclasses. 在不知道所有子类的情况下,您无法理解虚拟类的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM