当我运行此代码时:
struct X {
int a;
};
struct Y : public X {};
X x = {0};
Y Y = {0};
我得到:
error: could not convert ‘{0}’ from ‘<brace-enclosed initializer list>’ to ‘Y’
为什么大括号初始化适用于基类而不适用于派生类?
当我运行此代码时:
struct X {
int a;
};
struct Y : public X {};
X x = {0};
Y Y = {0};
我得到:
error: could not convert ‘{0}’ from ‘<brace-enclosed initializer list>’ to ‘Y’
为什么大括号初始化适用于基类而不适用于派生类?
C++ 17 之前的 C++ 标准版本的答案:
您的问题与聚合初始化有关:struct X
是聚合而struct Y
不是。这是关于聚合的标准报价(8.5.1):
聚合是一个数组或一个类(第 9 条),没有用户提供的构造函数(12.1),没有用于非静态数据成员的大括号或等号初始化器(9.2),没有私有或受保护的非静态数据成员(第 11 条),没有基类(第 10 条),也没有虚函数(10.3)。
此子句指定如果 aclass
具有基类,则它不是聚合。在这里,struct Y
hasstruct X
作为基类,因此不能是聚合类型。
关于您遇到的特定问题,请从标准中获取以下条款:
当聚合由初始化列表初始化时,如 8.5.4 中所指定,初始化列表的元素被视为聚合成员的初始化,按递增的下标或成员顺序。每个成员都是从相应的初始化子句复制初始化的。如果 initializer-clause 是一个表达式并且需要一个窄化转换 (8.5.4) 来转换该表达式,则程序是非良构的。
当您这样做时X x = {0}
,聚合初始化用于初始化a
为0
. 但是,当您这样做时Y y = {0}
,由于struct Y
不是聚合类型,编译器将寻找合适的构造函数。由于没有一个隐式生成的构造函数(默认、复制和移动)可以对单个整数执行任何操作,因此编译器会拒绝您的代码。
关于这个构造函数查找,来自 clang++ 的错误消息更明确地说明了编译器实际上试图做什么(在线示例):
Y Y = {0};
^ ~~~
main.cpp:5:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const Y &' for 1st argument
struct Y : public X {};
^
main.cpp:5:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'Y &&' for 1st argument
struct Y : public X {};
^
main.cpp:5:8: note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided
请注意,有一个扩展聚合初始化以支持您的用例的提议,并将其纳入 C++17。如果我阅读正确,它会使您的示例对您期望的语义有效。所以...您只需要等待符合 C++17 的编译器即可。
这个问题仍然在谷歌搜索结果中,所以我会在这里说。在 C++17 中是可能的。只有无构造器,无虚拟,无私有/受保护,但对于派生的 PODS,现在是可能的。
注意:今年(2021)eclipse for STM32(CubeIDE)仍然不提供c++17的菜单选择,但可以手动设置,例如-std=gnu++17
C++14 及更低版本应在构造函数中使用默认初始化程序。
struct Base
{
int member1{-54};
std::string member2{"Base"};
};
struct OtherType : Base
{
OtherType = default;
OtherType(int i,std::string s, int j) : Base{i,s}, member3{j} {}
int member3{5};
};
int main()
{
OtherType ot{ 45, "other", 13} ;
OtherType ot = { 13, "heynow", -1};
OtherType ot;
std::cout << "{" << ot.member1
<< ", " << ot.member2
<< ", " << ot.member3 << "}\n";
return 0;
}
C++17 -20 最适合:
struct Base
{
int member1{-54};
std::string member2{"Base"};
};
struct OtherType : Base
{
int member3{5};
};