Объектно-ориентированное программирование, конструктор копирования наследования - PullRequest
3 голосов
/ 15 января 2010

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

main()
{
student sobj1("name", "computer science");
student sobj2=sobj1;
}

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

student sobj2=sobj1;

что происходит, эта строка вызывает конструктор копирования студента, который работает, но конструктор копирования базового класса в этом случае вызываться не будет (будет вызываться конструктор по умолчанию базового класса). Мой вопрос: почему?

Ответы [ 3 ]

4 голосов
/ 15 января 2010

vava его правила почти верны, вот более явная версия:

  • Вы не можете иметь экземпляр производного класса без предварительного конструирования подобъектов базового класса: все базисные операторы выполняются первыми . ( Ctor является сокращением для конструктор .)
  • Вы не можете ввести тело ctor без предварительного конструирования каждого члена этого класса: ctors всех членов выполняются после ctors баз .
  • Сгенерированный компилятором ctor по умолчанию использует ctors по умолчанию для баз и членов.
  • Созданный компилятором cctor делает для каждого члена копирование : используются все ctor для баз и членов. ( Cctor является сокращением для конструктора копирования .)
  • Оператор присваивания, сгенерированный компилятором , выполняет присваивание по элементам : используется оператор присваивания для баз и элементов. (Оператор присваивания также называется operator = и op = .)
  • При реализации ctor самостоятельно (любой ctor, включая ctor-копию), любая база или элемент без параметров инициализации будет использовать свой ctor по умолчанию (в инициализаторе ctor, часть с двоеточием и перед тело функции ctor).
  • Если ctor элемента данных по умолчанию тривиален (более или менее «если он сгенерирован компилятором»), и вы не указываете этот элемент в инициализаторе ctor, то значение этого элемента будет мусором.
    • Это указывает на то, как эти правила все еще слишком упрощены; см. 12.6.2 / 3-4 в стандарте C ++ для изысканных подробностей.
    • Это относится только к элементам данных с тривиальными ctors по умолчанию.
    • Базовые классы с тривиальными ctors по умолчанию всегда являются мусором.

Пример vava, указывающий, что ctor копии персонажа полностью верен:

struct Student : Person {
  Student(Student const& other) : Person(other) {}
};

Примеры последней пули:

struct TrivialCtor { int n; };
struct A {
  TrivialCtor m;
  A() {}          // m.n is garbage
  A(int) : m() {} // m.n is 0

  friend ostream& operator<<(ostream& s, A const& v) {
    s << "m.n = " << v.m.n;
    return s;
  }
};

int main() {
  cout << "()   : " << A() << '\n';
  cout << "(int): " << A(42) << '\n';
  return 0;
}
3 голосов
/ 15 января 2010

Я считаю, что правила следующие:

  1. Конструктор базового класса всегда должен вызываться перед конструктором производного класса.
  2. Вы можете выбрать, какой из конструкторов базового класса будет вызываться, явно вызвав его в списке инициализации.
  3. Если вы этого не сделаете, вызывается конструктор по умолчанию.
  4. Когда у класса нет конструктора копирования, компилятор генерирует его. Он будет вызывать конструкторы по умолчанию для всех членов класса и конструктор копирования базового класса, так же, как это должен делать ваш рукописный конструктор.

Итак, поехали. Если вы не вызовете конструктор копирования базового класса, будет использован конструктор по умолчанию, НО компилятор достаточно умен, чтобы фактически вызвать его в своем собственном сгенерированном конструкторе копирования.

На всякий случай, если вы не знаете, как это назвать, есть пример

Student(Student const & p): Person(p) {
}
0 голосов
/ 15 января 2010

Роджер и Вава ответили на ваш технический вопрос.

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

Прежде всего потому, что нет смысла копировать сущности. В чем смысл копирования студента? Ни один!

Во-вторых, вам придется бороться с нарезкой при копировании ученика в человека, а затем обратно в ученика. И вам придется использовать обходные пути для поддержки назначения - наиболее известным из них является Envelop-letter Idiom .

Просто запретите копирование и присваивание в базовых классах с помощью наследования от класса, такого как boost :: noncopyable (для чистого решения C ++ 98/03), и обрабатывайте ваши сущности с помощью указателей. Если по какой-то странной причине вам действительно нужно дублировать сущности, взгляните на обычную функцию clone (), которая полагается на конструкторы защищенных копий.

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