【问题标题】:Use base class Copy CTOR in derived class在派生类中使用基类 Copy CTOR
【发布时间】:2018-11-09 10:53:27
【问题描述】:

我知道有很多关于这个主题的帖子,但我找不到可以完全回答我的问题的帖子。

假设我有一个基类和一个派生类,我为它实现了一个 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);
        .....
    }

现在我对这个设计有一些疑问。

  1. 这是适合这种情况的设计吗?
  2. 如果我在基类和派生类之间有第三个类,但它只包含原始类型,我应该将它们复制到哪里?例如。使用第二类的默认赋值运算符?建一个新的?只在第三层复制它们?
  3. 我可以类似地在派生类 Cctor 中调用基类 Cctor,而不是赋值运算符。有什么不同?如果我将它们放在这两种方法中,它会尝试复制两次值吗?

编辑:澄清一下,设计是我在项目中给出的。我有指针,所以我必须使用深拷贝。

【问题讨论】:

  • 就我个人而言,我会为不必编写任何复制构造函数或复制赋值运算符而拍摄。如果您可以以默认工作的方式编写类,那么您不必担心任何事情。这称为rule of zero

标签: c++ oop


【解决方案1】:

这是适合这种情况的设计吗?

不,通常不会。更惯用的方法是停止手动管理内存,如 char* name 并使用 std::string 或其他正确的类型:

Class Base {
    std::string name;
    ....
    Base(const Base& other) = default;
    Base& operator=(const Base& other) = default;
};

(请注意,赋值运算符应该返回对类的引用,而不是void)。

或者将内存管理封装在一个专门用于该目的的类设计中(但std::string 已经是那种类型了)。

如果你真的真的需要以愚蠢的容易出错的方式来做,那么实现你的复制构造函数来进行复制:

    Base(const Base& other) { / * deep copy of name */ }

然后将赋值实现为复制和交换:

    Base& operator=(const Base& other)
    {
      Base tmp(other);
      this->swap(tmp);
      return *this;
    }

这意味着您需要一个便宜的、不会抛出的 swap(Base&) 成员函数。

在任何情况下,派生类型的复制构造函数都是愚蠢的。您有一个正确的基类复制构造函数,所以它应该是:

Derived(const Derived& other) : Base(other) { }

并且赋值可以使用基础赋值:

Derived& operator=(const Derived& other)
{
   Base::operator=(other);
   return *this;
}

但是手动编写这些是不必要的,你可以默认它的复制操作无论如何都会做正确的事情:

class Derived : public Base {
public:
    Derived(const Derived&) = default;
    Derived& operator=(const Derived& ) = default;

如果我在基类和派生类之间有第三个类,但它只包含原始类型,我应该将它们复制到哪里?例如。使用第二类的默认赋值运算符?建一个新的?只在第三层复制它们?

您也应该使用= default 定义该类的复制构造函数和赋值运算符。一旦您使用正确的行为使Base 可以安全复制,编写其他类来使用它就很简单了。默认行为将做正确的事。如果您需要对动态分配的内存等未由 RAII 类型正确管理的内容进行特殊处理,则只需手动定义这些操作。

我可以类似地在派生类 Cctor 中调用基类 Cctor,而不是赋值运算符。有什么区别?

如果要复制构造,请使用复制构造函数,而不是赋值。为工作使用正确的功能。

【讨论】:

  • 感谢您的回答。我确实有另一个,在我在基类和派生类之间有另一个类的情况下,它只包括原始数据成员,我应该显式调用第二个类 Cctor 吗?或者我如何也复制它的所有数据成员?
  • 我已经更新了答案以涵盖您问题的其他部分
  • 所以基本上你是说如果我使用默认的 Ctor 和赋值运算符,并且正确定义了 Base 类,那么第二个类也会复制 Base 类信息?所以在我的第三堂课 CCtor\operator 中,我需要打电话给第二堂课吗?
  • 特殊成员函数(如复制构造函数和复制赋值运算符)的默认实现正确地复制了基类和成员。编译器比你更懂 C++,所以会做正确的事。所以让你的基类正常工作,并让派生类依赖它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-04
  • 2017-03-12
  • 1970-01-01
  • 2019-07-25
  • 2019-07-25
相关资源
最近更新 更多