Каковы правила для вызова конструктора суперclassа?

Каковы правила C ++ для вызова конструктора суперclassа из подclassа?

Например, я знаю в Java, вы должны сделать это как первую строку конструктора подclassа (и если вы этого не сделаете, подразумевается неявный вызов супер-конструктора no-arg), что дает вам ошибку компиляции, если это отсутствует) ,

Конструкторы базового classа автоматически вызываются для вас, если у них нет аргументов. Если вы хотите вызвать конструктор суперclassа с аргументом, вы должны использовать список инициализации конструктора подclassа. В отличие от Java, C ++ поддерживает множественное наследование (к лучшему или худшему), поэтому базовый class должен называться по имени, а не «super ()».

class SuperClass { public: SuperClass(int foo) { // do something with foo } }; class SubClass : public SuperClass { public: SubClass(int foo, int bar) : SuperClass(foo) // Call the superclass constructor in the subclass' initialization list. { // do something with bar } }; 

Подробнее о списке инициализации конструктора здесь и здесь .

В C ++ конструкторы no-arguments для всех суперclassов и переменных-членов вызываются для вас, прежде чем вводить ваш конструктор. Если вы хотите передать им аргументы, для этого называется отдельный синтаксис, называемый «цепочка конструктора», который выглядит следующим образом:

 class Sub : public Base { Sub(int x, int y) : Base(x), member(y) { } Type member; }; 

Если что-то запустится в этот момент, базы / члены, которые ранее завершили строительство, вызвали деструкторы, и исключение было обращено к вызывающему. Если вы хотите поймать исключения во время цепочки, вы должны использовать блок try функции:

 class Sub : public Base { Sub(int x, int y) try : Base(x), member(y) { // function body goes here } catch(const ExceptionType &e) { throw kaboom(); } Type member; }; 

В этой форме обратите внимание, что блок try является телом функции, а не находится внутри тела функции; это позволяет ему перехватывать исключения, вызванные неявными или явными инициализациями членов и базового classа, а также во время тела функции. Однако, если блок catch функции не генерирует другое исключение, среда выполнения перезапустит исходную ошибку; исключения во время инициализации нельзя игнорировать.

В C ++ существует концепция списка инициализации конструктора, где вы можете и должны вызывать конструктор базового classа и где вы также должны инициализировать элементы данных. Список инициализации появляется после подписи конструктора после двоеточия и перед телом конструктора. Допустим, у нас есть class A:

 class A : public B { public: A(int a, int b, int c); private: int b_, c_; }; 

Тогда, если B имеет конструктор, который принимает int, конструктор A может выглядеть так:

 A::A(int a, int b, int c) : B(a), b_(b), c_(c) // initialization list { // do something } 

Как вы можете видеть, конструктор базового classа вызывается в списке инициализации. Инициализация членов данных в списке инициализации, кстати, предпочтительнее назначать значения для b_ и c_ внутри тела конструктора, поскольку вы сохраняете дополнительную стоимость назначения.

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

Единственный способ передать значения родительскому конструктору – это список инициализации. Список инициализации реализуется с помощью: и затем списка classов и значений, которые должны быть переданы этому конструктору classов.

 Class2::Class2(string id) : Class1(id) { .... } 

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

Если у вас есть конструктор без аргументов, он будет вызван до выполнения конструктора производного classа.

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

 class base { public: base (int arg) { } }; class derived : public base { public: derived () : base (number) { } }; 

Вы не можете построить производный class без вызова родительского конструктора в C ++. Это происходит автоматически, если это не-arg C’tor, это происходит, если вы вызываете производный конструктор напрямую, как показано выше, или ваш код не будет компилироваться.

Все упомянули вызов конструктора через список инициализации, но никто не сказал, что конструктор родительского classа можно вызывать явно из тела конструктора производного члена. См. Вопрос Вызов конструктора базового classа из тела конструктора подclassа , например. Дело в том, что если вы используете явный вызов родительского classа или конструктора суперclassов в теле производного classа, это на самом деле просто создает экземпляр родительского classа и не вызывает конструктор родительского classа на производном объекте , Единственный способ вызвать родительский class или конструктор суперclassов в объекте производного classа – через список инициализации, а не в тело конструктора производного classа. Поэтому, возможно, его нельзя назвать «вызовом конструктора суперclassа». Я поставил здесь этот ответ, потому что кто-то может запутаться (как и я).

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

 using namespace std; class Base { public: Base(int a=1) : _a(a) {} protected: int _a; }; class Derived : public Base { public: Derived() {} void printit() { cout << _a << endl; } }; int main() { Derived d; d.printit(); return 0; } 

Выход: 1

 CDerived::CDerived() : CBase(...), iCount(0) //this is the initialisation list. You can initialise member variables here too. (eg iCount := 0) { //construct body } 

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

  • Должен ли я избегать многозадачного (конкретного) наследования в Django любыми способами?
  • Когда мне нужно использовать интерфейсы вместо абстрактных classов?
  • доступ к защищенному члену базового classа в другом подclassе
  • Наследование в Java - создание объекта подclassа вызывает также конструктор суперclassа. Почему именно?
  • Как интерфейсы заменяют необходимость множественного наследования при наличии существующих classов
  • Наследование в статических методах
  • «Не объявлена ​​в этой области» ошибка с шаблонами и наследованием
  • модификаторы доступа к Java и методы переопределения
  • Наследование с помощью конструктора базового classа с параметрами
  • Статический polymorphism C ++ (CRTP) и использование typedefs из производных classов
  • Разница между наследованием и композицией
  • Давайте будем гением компьютера.