我有自定义复制构造函数的基类,它负责处理已分配的内存。 我也从那个基地开过课。派生类没有对内存做更多的事情。
如何复制构造函数在dervied类中查找? 如何覆盖交换,移动和分配?
答案 0 :(得分:3)
除了swap
之外,您不应该做任何其他事情。在这方面,基类就像数据成员,编译器生成的复制构造函数和赋值(如果适用则移动)包括它。
swap
是不同的,因为没有编译器生成的swap
,只是命名空间std
中的默认实现,然后是程序员为用户定义的类型定义的任何特化或ADL重载
所以如果已经有一个看起来像这样的函数:
namespace foo {
void swap(Base &lhs, Base &rhs) {
lhs.swap(rhs); // or maybe the gory details are in this function
}
}
你什么都不做,有些用户称之为:
foo::swap(derived1, derived2);
然后基础部分将被交换,派生的部分将不会,这是非常糟糕的。
用户不应该像那样调用交换,但你知道用户是什么样的。如果Base
和Derived
位于同一名称空间中,对用户来说可能看起来特别诱人,他们只是假设它一切正常。因此,如果您认为您的用户(或您自己的代码库)在调用Derived
的方式中没有原则,那么您可能希望确保swap
超载以阻止它们。
用户应拨打swap
,如:
using std::swap;
swap(base1, base2);
swap(derived1, derived2);
当foo::swap
与Base
一起使用时,std::swap
会调用Derived
。 std::swap<Derived>
可能效率低下(如果Base
为实现效率而实施了交换,那么Derived
也应该这样做。因此,您可能也希望为swap
实现Derived
,但速度慢并不像错误那么糟糕。
那就是说,你问的是移动。如果Derived
可以有效移动,那么std::swap<Derived>
也不错。也许它可以改进,也许不是,但它应该是边缘的,因为三个动作很难被击败。
您和用户也应该意识到swap
不能很好地处理多态(因为通常两个对象必须具有相同的完整类型才能交换它们才有意义),并为基础实现它上课可能会带来麻烦。
Derived d1, d2;
Base &b1 = &d1, &b2 = d2;
swap(b1, d2); // swaps just the base part
swap(b1, b2); // swaps just the base part
首先,用户需要知道不要像那样调用swap。其次,您可能需要考虑具有Base
的{{1}}是否真的设计为基类。
答案 1 :(得分:1)
有所谓的五阶规则(以前称为三阶规则),它表示如果你有用户定义的任何规则:
比您可能还想要用户定义其他四个。
另一方面,有rule-of-zero:您可以使用自动处理这些事情的资源对象(RAII),而不是定义这五个特殊成员函数。
这样的对象是某个类C
的数据成员还是基类(子对象)并不关心:隐式声明的&amp;由编译器提供的C
定义的特殊成员函数将调用此资源对象的特殊成员函数,这很可能就足够了。
提示:可以为特定示例提供更精确的答案
答案 2 :(得分:0)
你不能“覆盖”构造函数。它不是C ++词汇表中的术语。你可以覆盖一个函数,但只有它是虚函数。
通常,您不应该在任何正确编写的基类的子构造函数中做任何特殊操作。让每一代人都照顾好自己。