Правило трех и наследство - PullRequest
4 голосов
/ 25 октября 2011

class A определяет оператор копирования, деструктор и оператор =. ( Правило Трех )

Если B наследуется от A:

  • деструктор будет вызываться автоматически
  • Мне нужно связать конструктор
  • operator= ... я должен определить это явно для класса B?

Ответы [ 5 ]

6 голосов
/ 25 октября 2011

Нет, это не нужно.

Если вы внимательно прочитаете Правило Три, вы заметите, что ничего не сказано о базовом классе, решение принимается исключительно на основе соответствующих атрибутов и поведения класса.

(проверьте этот пример на ideone)

#include <iostream>

struct A {
  A(): a(0) {}
  A& operator=(A const& rhs) { a = rhs.a; return *this; }
  int a;
};

struct B: A { B(): b(0) {} int b; };

int main() {
  B foo;
  foo.a = 1;
  foo.b = 2;

  B bar;
  bar = foo;

  std::cout << bar.a << " " << bar.b << "\n";
}

// Output: 1 2

Это на самом деле истинная сила инкапсуляции . Поскольку вам удалось, используя Правило трех , настроить поведение базового класса sane , его производные классы не должны знать, является ли конструктор копирования по умолчанию компилятором или реализован вручную (и сложный), все, что имеет значение для пользователя (а производный класс является пользователем), заключается в том, что конструктор копирования выполняет копирование.

Правило трех напоминает нам о деталях реализации , помогающих достичь правильной семантики. Как и все детали реализации, это имеет значение только для разработчика и сопровождающего этого класса.

2 голосов
/ 25 октября 2011

То же правило трех применимо и к производному классу.
Правило применимо ко всем классам, и вы можете применять его к каждому классу по иерархии наследования так же, как применяете его к отдельному классу.

Если вашему class B требуется какой-либо из двух ( Конструктор копирования и деструктор ) из Большая тройка , то вам также необходимо определить оператор назначения копирования.

Так что на самом деле это зависит от членов класса Derived и поведения, которое вы хотите для своих объектов класса Derived.

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

1 голос
/ 25 октября 2011

То, что Алс говорит, правильно, но я не уверен, что он отвечает на ваш вопрос. Если нет ничего конкретного, что вы хотите сделать в B, кроме того, что вы уже делаете в большой тройке A, то нет никакой причины, по которой вам следует определять и большую тройку B.

Однако если вам нужен один из них, следует применить правило трех.

1 голос
/ 25 октября 2011

деструктор будет вызываться автоматически

Еще лучше определить деструктор в производном классе B, для согласованности

Мне нужно объединитьконструктор

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

operator = ... я должен явно определить его для класса B?

Да, что-токак это:

struct A
{
  A& operator=( const A & r )
  {
    // assign all A's member variables
    return *this;
  }
};

struct B : public A
{
  B& operator=( const B & r )
  {
    A::operator=( r );
    // assign all B's member variables
    return *this;
  }
};
0 голосов
/ 25 октября 2011

Это пример кода и вывод:

#include <iostream>

class A{
 int a;
 public:
 A():a(0){}
 A(A const & obj){std::cout << "CC called\n"; a = obj.a;}
 A & operator =(A & a){std::cout << "operator= called\n"; return a;}
 ~A(){std::cout << "A::dtor called\n";}
};

class B: public A{
};

int main(){ 
 B b,v;
 b=v;
}

Выход:

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