继承构造函数在 C++ 中有多有用?
当我参加 C++ 标准委员会会议时,他们正在讨论删除 继承构造函数,因为还没有编译器供应商实现它(感觉是用户还没有要求它)。
让我快速提醒大家什么是继承构造函数:
struct B
{
B(int);
};
struct D : B
{
using B::B;
};
一些供应商建议,使用右值引用和可变参数模板(完美的转发构造函数),在继承类中提供转发构造函数将很简单,从而避免继承构造函数。
例如:
struct D : B
{
template<class ... Args>
D(Args&& ... args) : B(args...) { }
};
我有两个问题:
1)您能否提供您的编程经验中的真实世界(非人为的)示例,这些示例将从继承构造函数中受益匪浅?
2)您认为是否存在任何技术原因导致“完美转发构造函数”无法成为适当的替代方案?
谢谢!
As I sit in the C++ Standards committee meetings, they are discussing the pros and cons of dropping Inheriting Constructors since no compiler vendor has implemented it yet (the sense being users haven't been asking for it).
Let me quickly remind everyone what inheriting constructors are:
struct B
{
B(int);
};
struct D : B
{
using B::B;
};
Some vendors are proposing that with r-value references and variadic templates (perfect forwarding constructors), it would be trivial to provide a forwarding constructor in the inheriting class that would obviate inheriting constructors.
For e.g.:
struct D : B
{
template<class ... Args>
D(Args&& ... args) : B(args...) { }
};
I have two questions:
1) Can you provide real world (non-contrived) examples from your programming experience that would benefit significantly from inheriting constructors?
2) Are there any technical reasons you can think of that would preclude "perfect forwarding constructors" from being an adequate alternative?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我在这里展示了这种完美转发方法的一个问题: Forwarding all constructors in C+ +0x。
此外,完美的转发方法不能“转发”基类构造函数的显式性:它要么始终是转换构造函数,要么从不,并且基类将始终直接初始化(始终使用所有构造函数,甚至是显式构造函数)的)。
另一个问题是初始化列表构造函数,因为您无法将
Args
推导为initializer_list
。相反,您需要使用B{args...}
转发到基类(注意大括号),并使用(a, b, c)
或{1, 2, 3}
或= {1, 2, 3}
。在这种情况下,Args
将是初始值设定项列表的元素类型,并将它们转发到基类。然后初始化列表构造函数可以接收它们。这似乎会导致不必要的代码膨胀,因为模板参数包可能包含针对每种不同类型和长度组合的大量类型序列,并且因为您必须选择初始化语法,这意味着:I have shown one problem with that perfect forwarding approach here: Forwarding all constructors in C++0x .
Also, the perfect forwarding approach can't "forward" the expliciteness of base-class constructors: Either it is always a converting constructor or never, and the base-class will always be direct initialized (always making use of all constructors, even explicit ones).
Another problem are initializer-list constructors because you can't deduce
Args
toinitializer_list<U>
. Instead, you would need to forward to the base withB{args...}
(note the braces) and initializeD
objects with(a, b, c)
or{1, 2, 3}
or= {1, 2, 3}
. In that case,Args
would be the element types of the initializer list, and forward them to the base class. A initializer-list constructor can then receive them. This seems to cause unnecessary code bloat because the template argument pack will potentially contain lots of type sequences for each different combination of types and length and because you have to choose an initialization syntax this means:所提出的解决方法有几个缺点:
总体而言,该解决方法的认知复杂性非常非常糟糕。比默认的特殊成员函数要糟糕得多,为此添加了简单的语法。
构造函数继承的现实动机:使用重复继承而不是多重继承实现 AOP 混合。
A couple drawbacks to the proposed workaround:
Overall, the cognitive complexity of the workaround is very very bad. Much worse than e.g. defaulted special member functions, for which a simple syntax was added.
Real-world motivation for constructor inheritance: AOP mix-ins implemented using repeated inheritance instead of multiple inheritance.
除了其他人所说的之外,请考虑这个人为的示例:
至少在 MinGW g++ 4.4.1 中,由于 C++0x 构造函数转发,编译失败。
它可以通过“手动”转发(注释掉构造函数)很好地编译,并且可能/可能也可以使用继承的构造函数?
干杯&嗯。
In addition to what others have said, consider this artifical example:
At least with MinGW g++ 4.4.1, compilation fails due to the C++0x constructor forwarding.
It compiles fine with the "manual" forwarding (commented out constructors), and presumably/possibly also with inherited constructors?
Cheers & hth.
当新类具有需要在构造函数中初始化的成员变量时,我发现一个问题。这是常见的情况,因为派生类通常会向基类添加某种状态。
也就是说:
对于那些试图解决它的人:如何区分
:B(a), m(b)
和:B(b), m(a)
?你如何处理多重继承?虚拟继承?如果只解决最简单的情况,在实践中的用处就非常有限。难怪编译器供应商还没有实施该提案。
I see a problem when the new class has member variables that need to be initialized in the constructor. This will be the common case, as usually a derived class will add some sort of state to the base class.
That is:
For those trying to solve it: how do you distinguish between
:B(a), m(b)
and:B(b), m(a)
? How do you handle multiple inheritance? virtual inheritance?If only the most simple case is solved, it will have very limited usefulness in practice. No wonder the compiler vendors haven't implemented the proposal yet.
从哲学上讲,我反对继承构造函数。如果您正在定义一个新类,那么您就是在定义它的创建方式。如果大部分构造可以在基类中进行,那么将这项工作转发给初始化列表中的基类构造函数是完全合理的。但你仍然需要明确地这样做。
Philosophically, I'm against inheriting constructors. If you're defining a new class, you're defining how it's going to be created. If most of that construction can take place in the base class, then it's totally reasonable for you to forward that work to the base class' constructor in the initialization list. But you still need to explicitly do it.