简短回答:是的,您需要重复 D 中的工作
长答案:
如果您的派生类“D”不包含新成员变量,则默认版本(由编译器生成应该可以正常工作)。默认复制构造函数将调用父复制构造函数,默认赋值运算符将调用父赋值运算符。
但是,如果您的“D”类包含资源,那么您将需要做一些工作。
我发现您的复制构造函数有点奇怪:
B(const B& b){(*this) = b;}
D(const D& d){(*this) = d;}
通常复制构造函数链,以便它们是从基础向上复制构造的。在这里,因为您正在调用赋值运算符,所以复制构造函数必须调用默认构造函数来默认从下向上初始化对象。然后你再次使用赋值运算符。这似乎相当低效。
现在,如果你做一个作业,你是从下往上(或自上而下)复制的,但你似乎很难做到这一点并提供强有力的例外保证。如果在任何时候资源复制失败并且您抛出异常,则该对象将处于不确定状态(这是一件坏事)。
通常我看到它是反过来的。
赋值运算符是根据复制构造函数和交换定义的。这是因为它更容易提供强大的异常保证。我认为您无法通过这种方式提供强有力的保证(我可能是错的)。
class X
{
// If your class has no resources then use the default version.
// Dynamically allocated memory is a resource.
// If any members have a constructor that throws then you will need to
// write your owen version of these to make it exception safe.
X(X const& copy)
// Do most of the work here in the initializer list
{ /* Do some Work Here */}
X& operator=(X const& copy)
{
X tmp(copy); // All resource all allocation happens here.
// If this fails the copy will throw an exception
// and 'this' object is unaffected by the exception.
swap(tmp);
return *this;
}
// swap is usually trivial to implement
// and you should easily be able to provide the no-throw guarantee.
void swap(X& s) throws()
{
/* Swap all members */
}
};
即使您从 X 派生一个 D 类,这也不会影响此模式。
诚然,您需要通过显式调用基类来重复一些工作,但这相对来说是微不足道的。
class D: public X
{
// Note:
// If D contains no members and only a new version of foo()
// Then the default version of these will work fine.
D(D const& copy)
:X(copy) // Chain X's copy constructor
// Do most of D's work here in the initializer list
{ /* More here */}
D& operator=(D const& copy)
{
D tmp(copy); // All resource all allocation happens here.
// If this fails the copy will throw an exception
// and 'this' object is unaffected by the exception.
swap(tmp);
return *this;
}
// swap is usually trivial to implement
// and you should easily be able to provide the no-throw guarantee.
void swap(D& s) throws()
{
X::swap(s); // swap the base class members
/* Swap all D members */
}
};