2013-07-24 3 views
3

Я очень новичок в C++, но я исхожу из фона Java, поэтому я понимаю большинство концепций OOP. Я читаю через вводное руководство, и я наткнулся на этот пример:Список инициализаторов наследования C++

[Foo.H] 
class A 
{ 
    public: 
     A(int something); 
}; 

class B : public A 
{ 
    public: 
     B(int something); 
}; 

[Foo.C] 
#include "Foo.H" 

A::A(int something) 
{ 
    printf("Something = %d\n", something); 
} 

B::B(int something) : A(something) 
{ 
} 

правильно ли считать, что при прохождении A(something) к списку инициализаторе B::B(int something) он похож на super ключевое слово в Java - он же, он выполнит код A::A(int something)? Кроме того, почему я только звоню A(something) вместо A::A(something) из списка инициаторов?

В основном я спрашиваю: это выше эквивалентно следующему:

B::B(int something) 
{ 
    A::A(something) 
} 

Позвольте мне расширить, почему я смущен.

Если бы я должен был использовать:

B::B(int something) : A(something) 
{ 
    int x = 5; 
    printf("x = %d", x); 
} 

Позвони код через

B::B(7); 

Будет ли это распечатывают x = 5 или something = 7 первым? И почему он должен выполняться в этом порядке?

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

+0

Это обычно считается вежливым ждать ~ 24 часов, чтобы отметить ответ, как принято, чтобы дать людям время, чтобы увидеть и ответить правильно –

ответ

2

Да, A(something) передает это значение, как super. Вам не нужно использовать A::A, потому что язык автоматически вводит имя базового класса в дочерний класс.

Это, однако, не эквивалентно

B::B(int something) 
{ 
    A::A(something) 
} 

, потому что это не юридический кодекс. Вы можете выбрать, какой родительский конструктор вызывать в списке инициализаторов.

Что касается вашего вопроса о печати ... вы попробовали? Вы увидите, что сначала печатают родительский something=, а затем x=.

+0

у меня нет C++ компилятор в настоящее время. Я просто читаю литературу по основам. Спасибо за короткое, но всеобъемлющее объяснение! – MrHappyAsthma

1

нет, они не эквивалентны

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

B::B(int something) {} неявно вызывает A::A(), и если A не имеет конструктора по умолчанию, он не будет скомпилирован.

B::B(int something) 
{ 
    A::A(something) 
} 

, что это делает то, что он пытается вызвать A::A() неявно в списке инициализации, а затем вызвать A::A(something), как вы знаете, что это не будет компилироваться данными A не имеет конструктора по умолчанию.

так что если вы хотите вызвать другой родительский конструктор единственный способ сделать это состоит в списке инициализатора а именно

B::B(int something) : A(something) {} 
1
A::A(int something) 
{ 
    printf("Something = %d\n", something); 
} 

Это конструктор В. Первое, что конструктор делает это построить его базовые классы (в порядке, объявленном в классе, а не в порядке конструктора), а затем построить объекты-члены (в порядке, объявленном в классе, а не в порядке конструктора), а затем он выполняется тело (код в {}). Причина этого в том, что B- объект A, поэтому он должен быть полным A, прежде чем он может даже стать объектом B. И все члены должны быть полностью сконструированы перед выполнением кода какой-либо членской функции, иначе могут произойти плохие вещи. Таким образом, базовые классы и члены должны быть созданы до того, как тело конструктора может начаться.

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

B::B(int something) : A(something) 
{ 
    int x = 5; 
    printf("x = %d", x); 
} 

Вы не должны квалифицировать имя конструктора A, потому что мы уже находимся в контексте объекта B, а B уже знает о A.

B::B(int something) 
{ 
    A::A(something) 
} 

Этот код является недопустимым, поскольку B построит это A объект перед выполнением тела в {}. Поскольку A был уже построен, вызов A::A в теле не имеет смысла, и компилятор будет диагностировать это.

B::B(int something) : A(something) 
{ 
    int x = 5; 
    printf("x = %d", x); 
} 

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

something = 7 
x = 5 
Смежные вопросы