从继承的函数中调用虚函数?

时间:2014-09-06 13:34:44

标签: c++ inheritance polymorphism virtual-functions

我试图将它映射到我脑海中,但说实话,我不知道这里到底发生了什么。
当我在下面的示例中添加和删除虚拟关键字时,究竟发生了什么

#include <iostream>
#include <string>

class A {
public:
    A() { me = "From A"; }
    void caller() { func(); }
    virtual void func() { std::cout << me << std::endl; } // THIS LINE!
private:
    std::string me;
};

class B : public A {
public:
    B() { me = "From B"; }
    void func() { std::cout << me << std::endl; }
private:
    std::string me;
};

int main() {
    A a;
    a.caller();
    B b;
    b.caller();
    return 0;
}

使用虚拟关键字打印&#34;从A&#34;,然后&#34;从B&#34;。 如果没有虚拟关键字,则会打印&#34;从A&#34;,然后&#34;从A&#34;。

到目前为止,这是我唯一一次在没有指针的情况下使用虚拟功能。我认为如果删除了虚拟关键字,编译器会做标准的事情,即重载继承的函数并最终打印&#34;从A&#34;和&#34;从B&#34;反正。

我认为这比VTable更深入,而且更多的是它在特定情况下的行为方式。 B甚至有VTable吗?

3 个答案:

答案 0 :(得分:1)

电话

func()

相当于

this->func()

所以涉及的指针。

但是,没有必要让指针来理解行为。

即使直接打电话,例如当b.func()在静态已知类型中是虚拟的时,func必须使用,就像它是虚拟呼叫一样。编译器可以基于知道b的最派生类型来优化它。但这是一种不同的考虑因素(优化可以做任何事情)。

答案 1 :(得分:0)

在您的示例中,您不会看到差异:

  • 使用虚函数,编译器将通过VTable生成调用,并且在运行时,每个对象将为其真实类调用正确的函数。

  • 使用非虚函数,编译器在编译时根据对象定义的类确定要调用的正确函数。

现在尝试以下操作,以查看正在运行的虚拟功能:

A  *pa = &b;       // pointer to an A: valid as b is a B wich is also an A.  
pa -> caller();    // guess what will be called if virtual or not. 

无需指向试验虚拟功能的指针。你也可以用引用观察到相同的效果:

A& ra = b;       // create a reference to an A, but could as well be a parameter passed by reference.
ra.caller(); 

虚函数对于多态非常有用。这个想法是你使用类的一般对象,但是你在编译时不知道,如果在运行时对象真的属于这个类,或者它不是一个更特殊的对象(继承)来自班级)。

答案 2 :(得分:0)

除了虚拟发送的问题,可能带来额外混淆的是,你有两个me,一个在A中声明,另一个在B中声明。这是两个截然不同的对象。

B类型的对象有两个类型为std::string的数据成员;一个独立,一个纳入类型A的子对象。但是,后者不能立即在B类型的方法中使用,因为它的名称被此类中引入的新me所黯然失色(尽管您可以使用限定名称A::me引用它)。

因此,即使A::funcB::func的实体看起来相同,但两者中使用的标识符me都指向不同的成员。