我开始玩工会并通过编译c ++ 11常见问题解答中的一个简单示例而遇到麻烦。结果在这里讨论: c++11 unrestricted unions example
不,我再玩一些代码:
示例代码1:
class A
{
private: int a;
public:
A(): a(0) { cout << "Create A no args" << endl; }
};
class B
{
private: float b;
public:
};
class OneOfN
{
public:
union U
{
A a;
B b;
} u;
};
OneOfN n{}; // Compiles! That I did not expect, but the constructor will not be
// called! But why?
为了让事情变得更加奇怪,这里有两个联盟成员的示例2,其中没有人拥有默认构造函数!联盟本身也没有提供构造函数,但它编译并按预期工作。哇!
例2:
class A
{
private: int a;
public:
A(int _a): a(_a) { cout << "Create A with args" << endl; }
};
class B
{
private: float b;
};
class OneOfN
{
public:
union U
{
A a;
B b;
} u;
};
int main()
{
OneOfN n2{1}; // This compiles as expected, constructor A(int) is called! Fine!
// But we see later, this is not the truth!
};
问题:如果示例2的代码有效,为什么没有机会对联合成员使用给定的默认构造函数?使用带有parms的构造函数看起来没问题并按预期工作。对我来说很奇怪!
继续这个谜团并添加示例以在A类中再有一个数据成员我们遇到麻烦。见例3:
class A
{
private:
int a;
int aa;
public:
A( int _a, int _aa): a(_a), aa(_aa) { cout << "Create with 2 args" << endl; }
};
class B
{
private: float b;
public:
};
class OneOfN
{
public:
union U
{
A a;
B b;
} u;
};
int main()
{
OneOfN n3{2,3}; // Ups! Fails
};
盛衰!现在我们看到OneOfN实例的创建失败了。怎么了? 如例2所示,它不是被调用的构造函数A(int)!这是一个两步初!首先创建一个A,调用A(int),然后将该对象赋予复制构造函数!
因此,对示例3的以下更改使示例正常工作:
OneOfN n4{A{2,3}}; // Works! Ah! We use implicit the copy construction!
问题: 1)此代码有效吗?
2)为什么复制构造函数有效但默认构造函数没有?对我来说,它看起来很奇怪。
3)总是,如果没有手动编写union的默认构造函数,那么对于union的构造函数的参数是否会传递给FIRST union元素的复制构造函数,这是真的吗?
我打算给出这个三步示例,你可以抓住我的想法。因此,我希望这个例子能为其他初学者提供正确使用“无限制工会”的提示:-)对我来说,这种行为看起来很特别。
答案 0 :(得分:1)
部分的,一般性的答案:事情是他们的方式,因为关于语言设计的许多选择都是基于工程权衡,而不是基于理论上的可能。
“这些限制可以防止许多微妙的错误并简化工会的实施。后者非常重要,因为工会的使用通常是一种优化,我们不希望”隐藏成本“强加于此。 从具有构造函数(等)的成员的联合中删除构造函数(等)的规则使简单的联合变得简单并迫使程序员在需要时提供复杂的操作。“(C ++编程语言) ,第215页)
此外,
“在需要时,用户可以定义一个包含联合的类,该联合使用构造函数,析构函数和赋值(第8.3.2节)正确处理联合成员。如果需要,这样的类也可以防止错误写一个成员然后读另一个成员。 可以为最多一个成员指定一个类内初始值设定项。如果是这样,此初始值设定项将用于默认初始化。“
上述参考文献的第8.3.2节以
开头“看看我们如何编写一个能够克服滥用工会问题的课程”[...]
因此值得一读。