Достаточно ли удаления копий и перемещения конструкторов / операторов присваивания в базовом классе? - PullRequest
2 голосов
/ 05 марта 2019

Если у меня есть абстрактный базовый класс, и я хочу сделать все производные классы некопируемыми и неподвижными, достаточно ли объявить эти специальные функции-члены удаленными в базовом классе?Я хочу убедиться, что вся моя иерархия классов не копируется и не может быть перемещена, и мне интересно, смогу ли я избежать необходимости объявлять эти 4 специальные функции-члены удаленными в каждом производном классе.Я видел SO-ответ, в котором казалось, что производный класс может явно объявить конструктор копирования или перемещения, несмотря на то, что он был удален из базового класса, но в следующем примере возникает ошибка компиляции, когда я пытаюсь определить оператор назначения дефолтной копии, поэтому яЯ не уверенЭто ошибка:

производный_класс.cc: 15: 15: ошибка: по умолчанию этот конструктор копирования удалит его после первого объявления DerivedClass :: DerivedClass (const DerivedClass &) = default;

производный_класс.h: 9: 22: примечание: конструктор копирования DerivedClass неявно удаляется, поскольку базовый класс virtual_functions :: BaseClass имеет класс конструктора удаленных копий DerivedClass: public BaseClass {

base_class.h: 11: 3: примечание: «BaseClass» был явно помечен как удаленный здесь BaseClass (const BaseClass &) = delete;

// base_class.h
class BaseClass {
public:
  BaseClass(const BaseClass &) = delete;
  BaseClass(BaseClass &&) = delete;
  BaseClass &operator=(const BaseClass &) = delete;
  BaseClass &operator=(BaseClass &&) = delete;
  virtual ~BaseClass() = default;
  virtual bool doSomething() = 0;

protected:
  BaseClass(std::string name);

private:
  std::string name_;
};

// derived_class.h
class DerivedClass : public BaseClass {
public:
  DerivedClass();
  DerivedClass(const DerivedClass &);
  bool doSomething() override;
};

// derived_class.cc
DerivedClass::DerivedClass(const DerivedClass &) = default;

Ответы [ 3 ]

5 голосов
/ 05 марта 2019

Достаточно ли удаления конструкторов / операторов присваивания и перемещения в базовом классе?

Достаточно предотвратить неявно сгенерированные операции копирования и перемещения конструкторов / операторов присваивания.

Я видел SO-ответ, в котором, казалось, подразумевалось, что производный класс мог явно объявить конструктор копирования или перемещения, несмотря на то, что был удален из базового класса

Это правильно,Вы не можете предотвратить это.Ну, вы можете предотвратить это, объявив финал класса.Тогда не может быть производных классов, и, следовательно, производные классы не могут быть копируемыми.

Конечно, такой явно объявленный конструктор копирования (и другие) не сможет скопировать базовый подобъект, который не подлежит копированию.Конструкторы должны использовать BaseClass(std::string), и операторы присваивания не могут каким-либо образом изменять состояние базового объекта (если они не используют какой-то трюк, чтобы обойти инкапсуляцию спецификатора доступа).

4 голосов
/ 05 марта 2019

Вы не можете запретить дочернему классу определять собственный конструктор копирования / перемещения. Тем не менее, это предотвратит его «из коробки», то есть если вы его не предоставите или используете встроенный конструктор по умолчанию, он также будет помечен как удаленный. Причина, по которой вы получаете ошибку здесь, когда вы пытаетесь просто определить конструктор по умолчанию, заключается в том, что вам не разрешено делать это во внешнем определении, когда член или база неявно удалили его. Если бы вы использовали

class DerivedClass : public BaseClass {
public:
  DerivedClass(const DerivedClass &) = default;
  bool doSomething() override;
};

тогда код скомпилируется, и вы получите ошибку только в том случае, если попытаетесь вызвать конструктор копирования. Это работает, потому что встроенное неявное значение по умолчанию разрешено, даже если член или база неявно удаляют его, а конечным результатом является то, что конструктор неявно удаляется.

1 голос
/ 05 марта 2019

Вы не можете запретить производному классу объявлять конструкторы копирования / перемещения, но их нельзя использовать по умолчанию: ctor копирования по умолчанию или производный класс будут пытаться вызвать ctor копирования своей базы (то же самое для перемещения).

Но производный класс может явно построить свою базу с помощью ctor по умолчанию:

class DerivedClass : public BaseClass {
public:
  DerivedClass();
  DerivedClass(const DerivedClass &): BaseClass() {
      // copy ctor for the derived part
  }
  bool doSomething() override;
};

Et voila ... класс DerivedClass теперь можно копировать, несмотря на то, что его базовый класс - нет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...