Забранете функционалността, автоматично предоставена от 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 има още по-добра ключова дума за изтриване, налична за забрана на генерирани от компилатора членове:

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