虚拟继承是否强制基 class 是默认可构造的?
Does virtual inheritance force a base class to be default constructible?
在下面的代码中,编译器要求基 class X 是 默认可构造的。但是,如果我从 class 节点 的继承中删除 virtual 关键字,则对成员 的访问m_x 当然变得模棱两可,但是 默认构造函数 for class 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;
}
class 的初始化顺序如下 [class.base.init]:
In a non-delegating constructor, initialization proceeds in the following order:
— First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in
the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes,
where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
您的层次结构是 A --> Node<X> --> X
,因此首先要初始化的是 X
,因为它是一个虚拟基础 class。它未在您的内存初始化程序中指定,因此插入了隐式默认构造:
A( int i )
: X() // <== implicit
, Node< X >( i )
, m_a( i )
{
}
因为 X
不是默认可构造的,所以你会得到那个错误。您可以通过明确提供正确的内容来解决此问题:
A( int i )
: X(i)
, Node< X >( i )
, m_a( i )
{
您不必担心 X
被构造两次,因为虚拟基础 classes 仅针对 most 派生 class...这将是 A
而不是 Node<X>
.
从@Berry 的回答开始,修复代码的唯一方法是对虚拟继承的 X 构造函数进行显式调用。
但是,在classesA、B中显式调用X的构造是不够的,或者C: 基本上在每个class涉及的任何层次的继承中都必须调用!
棘手的是 Inheritance<> 可变参数模板 class:可变参数扩展的每一步都必须提供对 X 构造函数的显式调用。
这是在启用了 C++11 标志的 MinGW 4.9.2 上运行的代码:
#include <iostream>
template< typename T, typename V >
struct Node : virtual V
{
using Virtual = V; // Added this line
template< typename ...Args >
Node( Args... args )
: V( 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::Virtual( args... ) // added this line
, FirstBaseClass( args... )
, Inheritance< OtherBaseClasses... >( args... )
{ }
};
template < >
struct Inheritance< >
{
template< typename ...Args >
Inheritance( Args... args )
{ }
};
struct X
{
X(int i)
: m_x( i )
{ }
int m_x;
};
struct A : Node< A, X >
{
A( int i )
: X( i ) // added this line
, Node< A, X >( i )
, m_a( i )
{ }
int m_a;
};
struct B : Node< B, X >
{
B( int i )
: X ( i ) // added this line
, Node< B, X >( i )
, m_b( i )
{ }
int m_b;
};
struct C : Node< C, X >
{
C( int i )
: X ( i ) // added this line
, Node< C, X >( i )
, m_c( i )
{ }
int m_c;
};
struct Example : Inheritance< A, B, C >
{
Example( int i )
: X ( i ) // added this line
, 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;
}
在下面的代码中,编译器要求基 class X 是 默认可构造的。但是,如果我从 class 节点 的继承中删除 virtual 关键字,则对成员 的访问m_x 当然变得模棱两可,但是 默认构造函数 for class 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;
}
class 的初始化顺序如下 [class.base.init]:
In a non-delegating constructor, initialization proceeds in the following order:
— First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
您的层次结构是 A --> Node<X> --> X
,因此首先要初始化的是 X
,因为它是一个虚拟基础 class。它未在您的内存初始化程序中指定,因此插入了隐式默认构造:
A( int i )
: X() // <== implicit
, Node< X >( i )
, m_a( i )
{
}
因为 X
不是默认可构造的,所以你会得到那个错误。您可以通过明确提供正确的内容来解决此问题:
A( int i )
: X(i)
, Node< X >( i )
, m_a( i )
{
您不必担心 X
被构造两次,因为虚拟基础 classes 仅针对 most 派生 class...这将是 A
而不是 Node<X>
.
从@Berry 的回答开始,修复代码的唯一方法是对虚拟继承的 X 构造函数进行显式调用。
但是,在classesA、B中显式调用X的构造是不够的,或者C: 基本上在每个class涉及的任何层次的继承中都必须调用!
棘手的是 Inheritance<> 可变参数模板 class:可变参数扩展的每一步都必须提供对 X 构造函数的显式调用。
这是在启用了 C++11 标志的 MinGW 4.9.2 上运行的代码:
#include <iostream>
template< typename T, typename V >
struct Node : virtual V
{
using Virtual = V; // Added this line
template< typename ...Args >
Node( Args... args )
: V( 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::Virtual( args... ) // added this line
, FirstBaseClass( args... )
, Inheritance< OtherBaseClasses... >( args... )
{ }
};
template < >
struct Inheritance< >
{
template< typename ...Args >
Inheritance( Args... args )
{ }
};
struct X
{
X(int i)
: m_x( i )
{ }
int m_x;
};
struct A : Node< A, X >
{
A( int i )
: X( i ) // added this line
, Node< A, X >( i )
, m_a( i )
{ }
int m_a;
};
struct B : Node< B, X >
{
B( int i )
: X ( i ) // added this line
, Node< B, X >( i )
, m_b( i )
{ }
int m_b;
};
struct C : Node< C, X >
{
C( int i )
: X ( i ) // added this line
, Node< C, X >( i )
, m_c( i )
{ }
int m_c;
};
struct Example : Inheritance< A, B, C >
{
Example( int i )
: X ( i ) // added this line
, 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;
}