Функциональность Disallow, автоматически предоставляемая компиляторами C++

Скотт Мейерс в своей книге «Эффективный C++» говорит:

Чтобы запретить функциональность, автоматически предоставляемую компиляторами, объявите соответствующие функции-члены закрытыми и не давайте реализаций. Тогда, если кто-то непреднамеренно вызовет одну из них, он получит сообщение об ошибке во время компоновки.

Я попытался написать пример программы для достижения того, что пытался объяснить Скотт. Я мог добиться того же, даже когда функция-член была объявлена ​​public и не имела реализации. Ошибка ссылки возникла в моем случае также, когда я попытался инициализировать объект из другого объекта. Поэтому я не понимаю, почему Скотт подчеркивает необходимость объявления функции-члена private?

Моя примерная программа написана ниже:

#include <iostream>

using namespace std;

class Unique
{
   private:
      int num;

   public:
      Unique(int x)
      {
         num  = x;
      }
      Unique(const Unique &obj);

      Unique& operator =(const Unique &obj);

      void disp(void)
      {
         cout << "num = " << num << "\n";
      }
};

int main()
{
   Unique ob1(3);
   Unique ob2(ob1);

   ob1.disp();
   ob2.disp();

   return 0;
}

Я получаю следующую ошибку ссылки:

/tmp/ccXfqSqE.o(.text+0x135): В функции main': : undefined reference toUnique::Unique(Unique const&)' collect2: ld вернул 1 статус выхода


person nitin_cherian    schedule 19.11.2011    source источник


Ответы (3)


Ошибки компилятора более понятны и возникают раньше (это более заметно в больших проектах, скомпилированных из большого количества исходных файлов), чем ошибки ссылок. Кроме того, их легче читать в большинстве случаев. Объявление членов закрытыми провоцирует ошибки компиляции и поэтому предпочтительнее, чем оставлять члены неопределенными, чтобы запретить их.

Как отмечает Батист, в C++11 есть даже лучшее ключевое слово delete, доступное для запрета членов, сгенерированных компилятором:

class A
{
     A(constA&) = delete; // copy construction is not allowed
};
person Peter G.    schedule 19.11.2011
comment
Обратите внимание, что начиная с C++11 вы используете ключевое слово delete, чтобы убедиться, что конструктор или функция не используются. - person Baptiste Wicht; 19.11.2011

Если вы объявите их закрытыми, компилятор остановится, как только обнаружит, что кто-то пытается их вызвать, независимо от того, определена ли функция на самом деле (поскольку они не разрешены).

Объявив их общедоступными, вам придется подождать, пока этап компоновщика не получит вашу ошибку, поскольку это должен быть законный вызов, но с отсутствующим определением.

person Community    schedule 19.11.2011

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

Кстати, в C++11 мы знаем, что у нас есть официальный способ запретить компилятору генерировать для нас функции.

class Unique{
public:
    Unique() = delete;
}
person ComfortablyNumb    schedule 19.11.2011