【问题标题】:how to inline virtual with multiple inheritance如何使用多重继承内联虚拟
【发布时间】:2015-03-23 03:28:44
【问题描述】:

请不要抨击我,或者说我问这个问题是错误的,或者说多重继承是邪恶的。这个问题是为了更好地理解 C++ 编译器是如何工作的。我知道inline 语句用于提示编译器用源代码替换函数调用,编译器可以选择是否内联函数。如果您可以强制使用inline 功能,那会很棒,但这并不是我真正要解决的问题。我想要做的是能够创建一段代码,在一个地方编写并由编译器复制并粘贴到其他地方。我编写的代码如下所示:

struct base 
{
    virtual double eval() = 0; // should be no eval function for the
};

struct foo : public base
{
    virtual double eval() overrides
    {
          return //foo eval
    }
};

struct bar : public base
{
    virtual double eval() overrides
    {
          return //foo eval
    }
};

struct baz : public base
{
    virtual double eval() overrides
    {
          return //baz eval
    }
};

struct FooBarBaz : public foo, public bar, public baz
{
    virtual double eval() final
    {
          return foo::eval() + bar::eval() + baz::eval();
    }
};

编译器会生成与此等价的东西:

struct base 
{
    virtual double eval() = 0; // should be no eval function for the
};

struct foo : public base
{
    virtual double eval() overrides
    {
          return //foo eval
    }
};

struct bar : public base
{
    virtual double eval() overrides
    {
          return //foo eval
    }
};

struct baz : public base
{
    virtual double eval() overrides
    {
          return //baz eval
    }
};

struct FooBarBaz : public foo, public bar, public baz
{
    virtual double eval() final
    {
          return /*foo eval*/ + /*bar eval*/ + /*baz eval*/
    }
};

有人告诉我,使用<type_traits> 是解决此问题的方法,如果这是真的,我想知道如何获得所需的结果。如果没有,我想知道如何做到这一点

【问题讨论】:

  • 你知道编译器是否已经在执行你想要的吗?您是否尝试过设置优化级别,然后查看汇编语言列表?
  • 请原谅我的无知,但您如何看待inlined 代码与多重继承的不同工作方式?
  • 我对编译器持中立态度,并且对汇编语言有很好的理解。至于inline 代码,编译器将从使用基函数调用的代码中获取代码,并将代码粘贴到派生函数中,而不是通过 v-table 查找函数
  • foo::eval()bar::eval()baz::eval() 无论如何都不是虚拟呼叫,AFAIK。
  • 既然“代码写在一个地方,由编译器复制粘贴到其他地方”是内联的定义,你这样说没有意义当您想要“在一个地方编写并由编译器在其他地方复制和粘贴的代码”时,强制内联“并不是真正的问题”

标签: c++ c++11 inline multiple-inheritance typetraits


【解决方案1】:

编译器是否决定内联取决于它已编码的启发式算法……但没有理由不内联来自FooBarBaz::eval 的对foo::evalbar::evalbaz::eval 的调用,因为限定条件禁用动态调度。

也就是说,当编译器遇到限定调用foo::eval 时,它将执行该成员函数的最终覆盖程序foo 的级别。它不会使用vtable(无论如何都会以无限递归结束,因为最终的覆盖器将是FooBarBaz::eval

除此之外,您应该阅读虚拟继承FooBarBaz3base 类型的子对象,可能不是您想要的...

【讨论】:

  • 我喜欢你的回答,但是base 函数是一个纯抽象函数,仅提供一个标准接口,没有对所有派生对象的任何实现或数据,因此 虚拟继承除非我需要虚拟继承来让编译器做正确的事情,否则没有意义。
  • @vickoza:FooBarBaz fbz; base & b = fbz。错误:不明确的转换,因为有多个base,您要绑定哪个?用作接口的基是virtual继承的主要候选对象:如果有一个完整的对象并且恰好通过不同的继承路径实现了相同的接口,那很好,只有一个 实现协议的对象。
  • 谢谢,现在我明白了,我认为虚拟继承合并了基础实现,所以如果你有许多共享相同基础的对象,你只有一个基础,所以你是说我肯定定义 struct FooBarBaz : public virtual foo, public virtual bar, public virtual baz 如果是这样与使用继承相比,使用虚拟继承总是一个好主意
  • @vickoza:我没有说清楚,base 的继承应该是虚拟的(纯接口)。建立其他继承关系virtual 对您没有帮助,因为正如您所提到的,它仅有助于合并来自同一基础的不同路径中的继承。虚拟继承总是一个好主意,而且在很多情况下都会带来成本(对象的布局不固定)
猜你喜欢
  • 2017-03-31
  • 2015-11-21
  • 1970-01-01
  • 1970-01-01
  • 2013-11-19
  • 1970-01-01
  • 2014-10-12
  • 1970-01-01
  • 2011-10-15
相关资源
最近更新 更多