我知道这个主题有很多帖子,但我找不到任何完全回答我的问题.
假设我有一个Base类和一个Derived类,我为它实现了CCtor和赋值运算符,如下所示:
class Base {
char * name;
....
Base(const Base& other) :name(nullptr) { *this = other }
void operator=(const Base& other) { ... Deep copy of name }
}
class Derived : public Base {
....
Derived(const Derived& other) { *this = other ; }
void operator=(const Derived& other) {
Base::operator=(other);
.....
}
Run Code Online (Sandbox Code Playgroud)
现在我对这个设计有一些疑问.
编辑:只是为了澄清,设计是我在项目中给出的.我有指针所以我必须使用深层复制.
这是适合这种情况的合适设计吗?
不,通常不会.更惯用的方法是停止手动管理内存char* name和使用std::string或其他类型做正确的事情:
Class Base {
std::string name;
....
Base(const Base& other) = default;
Base& operator=(const Base& other) = default;
};
Run Code Online (Sandbox Code Playgroud)
(请注意,赋值运算符应该返回对类的引用,而不是void).
或者将内存管理封装在专门为此目的的类设计中(但std::string已经是那种类型).
如果你真的真的需要做哑容易出错,然后实现你的拷贝构造函数做复印:
Base(const Base& other) { / * deep copy of name */ }
Run Code Online (Sandbox Code Playgroud)
然后将赋值实现为copy-and-swap:
Base& operator=(const Base& other)
{
Base tmp(other);
this->swap(tmp);
return *this;
}
Run Code Online (Sandbox Code Playgroud)
这意味着你需要一个廉价的非投掷swap(Base&)成员函数.
在任何情况下,派生类型的复制构造函数都是愚蠢的.你有一个正确的基类复制构造函数,所以它应该是:
Derived(const Derived& other) : Base(other) { }
Run Code Online (Sandbox Code Playgroud)
赋值可以使用基本赋值:
Derived& operator=(const Derived& other)
{
Base::operator=(other);
return *this;
}
Run Code Online (Sandbox Code Playgroud)
但是手动编写这些是不必要的,你可以默认它的复制操作,无论如何都会做正确的事情:
class Derived : public Base {
public:
Derived(const Derived&) = default;
Derived& operator=(const Derived& ) = default;
Run Code Online (Sandbox Code Playgroud)
如果我有一个第三类,在基类和派生类之间,但它只包含原始类型,我在哪里复制它们?EG使用第二类的默认赋值运算符?建立一个新的?只在第三级复制它们?
您还应该使用该类的复制构造函数和赋值运算符= default.一旦你Base安全地复制了正确的行为,组成其他类来使用它是微不足道的.默认行为将是正确的事情.如果您需要对RAII类型无法正确管理的动态分配内存等特殊处理,则只需手动定义这些操作.
我可以类似地在派生类CCtor中调用基类CCtor,而不是赋值运算符.有什么不同?
如果要复制构造,则使用复制构造函数,而不是赋值.使用正确的功能来完成工作.