虚拟继承是否强制基类是默认可构造的?

时间:2015-11-06 19:27:38

标签: c++ variadic-templates template-meta-programming default-constructor virtual-inheritance

在以下代码中,编译器请求基本类X 默认可构造。但是,如果我从类节点的继承中删除虚拟关键字,则对成员 m_x 的访问权限变得模糊不清,但不再需要 X类默认构造函数

这是什么原因?

#include <iostream>

struct Apply
{
    template< typename T >
    struct Node : virtual T    // this line contains the virtual inheritance
    {
        template< typename ...Args>
        Node( Args... args )
            : T( args... )
        {}
    };

    template < typename ...BaseClasses>
    struct Inheritance;

    template < typename FirstBaseClass, typename ...OtherBaseClasses>
    struct Inheritance< FirstBaseClass, OtherBaseClasses... >   : FirstBaseClass
            , Inheritance< OtherBaseClasses... >
    {
        template< typename ...Args>
        Inheritance( Args... args )
            : FirstBaseClass( args... )
            , Inheritance< OtherBaseClasses... >( args... )
        {

        }
    };
};

template < >
struct Apply::Inheritance< >
{
    template< typename ...Args>
    Inheritance( Args... args ){}
};

struct X
{
    X(int i){}

    int m_x;
};

struct A : Apply::Node< X >
{
    A( int i )
        : Apply::Node< X >( i )
        , m_a( i )
    {

    }
    int m_a;
};


struct B : Apply::Node< X >
{
    B( int i )
        : Apply::Node< X >( i )
        , m_b( i )
    { }

    int m_b;
};

struct C : Apply::Node< X >
{
    C( int i )
        : Apply::Node< X >( i )
        , m_c( i )
    { }

    int m_c;
};

struct Example : Apply::Inheritance< A, B, C >
{
    Example( int i )
        : Apply::Inheritance< A, B, C >( i )
    { }

    void print( ) const
    {
        // this line needs the virtual inheritance
        std::cout << m_x << std::endl;

        std::cout << m_a << std::endl;
        std::cout << m_b << std::endl;
        std::cout << m_c << std::endl;
    }
};

int main()
{
    Example ex( 10 );

    ex.print( );

    return 0;
}

2 个答案:

答案 0 :(得分:5)

类的初始化顺序如下[class.base.init]:

  

在非委托构造函数中,初始化按以下顺序进行:
   - 首先,仅对最派生类(1.8)的构造函数,初始化虚拟基类   它们出现在基类的有向无环图的深度优先从左到右遍历中的顺序,   其中“从左到右”是派生类base-specifier-list中基类出现的顺序。

您的层次结构是A --> Node<X> --> X,因此初始化的第一件事是X,因为它是一个虚拟基类。它没有在mem-initializer中指定,因此插入了隐式默认构造:

A( int i )
    : X() // <== implicit 
    , Node< X >( i )
    , m_a( i )
{

}

由于X不是默认可构造的,因此您会收到该错误。你可以通过明确提供正确的东西来解决这个问题:

A( int i )
    : X(i)
    , Node< X >( i )
    , m_a( i )
{

您不必担心X被构造两次,因为虚拟基类只是为派生类构建的......这将是{{1而不是A

答案 1 :(得分:0)

从@Berry回答开始,修复代码的唯一方法是编写对虚拟继承的 X 构造函数的显式调用。

但是,在 A B C 类中明确调用X的构造是不够的:必须调用它基本上在每个类参与任何级别的继承!

棘手的是继承&lt;&gt; 可变参数模板类:可变参数扩展的每一步都必须提供对X构造函数的显式调用。

以下代码适用于 MinGW 4.9.2 并启用了C ++ 11标志:

{{1}}