调用姐妹类C ++的函数

时间:2016-06-06 08:51:03

标签: c++ inheritance multiple-inheritance override virtual-inheritance

请考虑以下代码:

#include <iostream>

class A
{
public:
    virtual void f() = 0;
    virtual void g() = 0;
};

class B : virtual public A
{
public:
    virtual void f()
    {
        g();
    }
};

class C : virtual public A
{
public:
    virtual void g()
    {
        std::cout << "C::g" << std::endl;
    }
};

class D : public C, public B
{
};

int main()
{
    B* b = new D;
    b->f();
}

以下程序的输出为C::g

编译器如何调用类B ??

的姐妹类的函数

4 个答案:

答案 0 :(得分:6)

N3337 10.3 / 9

  

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

动态类型是指针真正指向的类型,而不是声明指定类型的类型。

因此:

D d;
d.g(); //this results in C::g as expected

与:

相同
B* b = new D;
b->g();

因为B::fg()的调用({em>隐式)调用了this指针,其动态类型为{ {1}},来电解析为D,即D::f

如果你仔细观察,那就是上面代码中显示的(完全)相同的行为,只有C::f现在隐含 b代替。

这就是虚函数的重点。

答案 1 :(得分:2)

这是virtual的行为:B通过g调用f,但g在运行时解析(如f)。因此,在运行时,g的唯一可用覆盖DC

中实现的覆盖

答案 2 :(得分:1)

与所有虚函数一样,

g在运行时解析。由于D的定义方式,它被解析为C实现的任何东西。

如果您不想要这种行为,您应该调用g的非虚拟实现(您也可以从虚拟实体委托该功能),或者显式调用B'使用B::g()实现。

虽然如果你这样做,你的设计会比它可能需要的要复杂得多,所以试着找到一个不依赖所有这些技巧的解决方案。

答案 3 :(得分:0)

虚拟函数调用在运行时通过引用实例的VTable来解析。任何虚拟类都存在明显的VTable(因此,ABCD各有一个VTable。每个运行时实例都有一个指向其中一个表的指针,由其动态类型决定。

VTable列出了类中的每个虚函数,将其映射到应该在运行时调用的实际函数。对于正常继承,这些是按声明的顺序列出的,因此基类可以使用派生类的VTable来解析它声明的虚函数(因为派生类,按声明顺序列出函数,将具有所有基类的函数首先列在基类自己的VTable的相同顺序中。对于虚拟继承(如上所述),这稍微复杂一些,但实际上派生类中的基类仍然有自己的VTable指针,指向派生的VTable内的相关部分。

实际上,这意味着您的D课程VTable g条目指向C的实施。即使通过B静态类型进行访问,它仍会引用相同的VTable来解析g