2015-12-06 2 views
0

Я пытаюсь выполнить задание в своей книге, но я не понимаю выход. Когда основной код в программе выполняется выход:Наследование, почему два конструктора вызываются для базового класса, C++

B :: B (3)

B :: B() // почему это выводимый

B :: B (- 3)

D :: D (3)

Он получает это от вызова B::B(int n) {} первых, а затем B::B() {} сопровождаемой следующих два строк, которые я получаю. Таким образом, программа называется первой, поскольку она объявлена ​​как конструктор класса A в функции и ей нужно назначить значения, что я не получаю, это строка вывода 2, почему B::B() {} даже называется? он получает вызов как конструктор, но не должен просто вызвать конструктор с параметрами?

class B { 
public: 
    B(); //why is this called? 
    B(int n); 
}; 

// Definitions of B 
B::B() { 
    cout << "B::B()\n"; 
} 
B::B(int n) { 
    cout << "B::B(" << n << ")\n"; 
} 

class D : public B { 
public: 
    D(); 
    D(int n); 
private: 
    B b; 
}; 

// Definitions of D 
D::D() { 
    cout << "D::D()\n"; 
} 
D::D(int n) : B(n) { 
    b = B(-n); 
    cout << "D::D("<< n <<")\n"; 
} 

int main(int argc, const char * argv[]) { 
    // insert code here... 

    D d(3); 
    return 0;  
} 

ответ

3

Первый конструктор базового класса называется: B::B(3).
Затем конструктор для поля b называется: B::B().
Затем выполняется производное тело конструктора (после все поля построены).
Конструктор D сначала конструирует другой B на линии b = B(-n); (так печатается B::B(-3)), затем печатает D::D(3).

+0

Но почему конструктор для поля b называется? isnt B :: B (3) конструктор для b-поля? – user2076774

+0

Это конструктор базового класса. Производный класс неявно содержит объект базового класса. Ваш 'B b;' лишний, если вам нужен только один 'B'. – Pixelchemist

+2

@ user2076774 Нет, поле 'b' является полностью нормальным полем, которое не имеет ничего общего с базовым классом (за исключением того, что он по совпадению имеет один и тот же тип). – immibis

0

Ваш класс D содержит два объекта типа B.

  1. неявное B от наследования
  2. явный B член с именем b

Вы можете переписать конструктор

D::D(int n) : B(n) 
{ 
    b = B(-n); 
    cout << "D::D("<< n <<")\n"; 
} 

как

D::D(int n) : B(n), b() 
{ 
    b = B(-n); 
    cout << "D::D("<< n <<")\n"; 
} 

, где видно, откуда исходит B::B(). Таким образом, ваш вывод легко объясним:

B::B(3) // base constructor of `D` 
B::B() // default construction of `b` member 
B::B(-3) // explicit construction inside D::D(int) 
D::D(3) // D::D(int) 

Если вы пишете

D::D(int n) : B(n), b(-n) 
{ 
    cout << "D::D("<< n <<")\n"; 
} 

вместо этого, есть только

B::B(3) 
B::B(-3) 
D::D(3) 

слева.

адресация комментарий:

Imagine D выглядеть следующим образом:

class D : public B 
{ 
public: 
    D(int); 
}; 

с определением конструктора

D::D(int v) { std::cout << "foo with " << v; } 

затем, код

D d(3); 

печатает

B::B() 
foo with 3 

и это совершенно справедливо, пока B по умолчанию конструктивны.

Если B будет отсутствие конструктора по умолчанию вы получите ошибку компиляции, и вы хотели бы переписать определение D к

D::D(int v) : B(3) { std::cout << "foo with " << v; } 

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

+0

Итак, всякий раз, когда у вас есть производный класс, вызывающий конструктор, всегда ли он должен иметь конструктор для базового класса? Скажем, что D :: D (int n): B (n) {} был просто D :: D (int n) {} и распечатал строку вместо вызова объекта, возникла бы ошибка, так как поле данных «b» объект не включен? – user2076774

+0

@ user2076774 См. Мое редактирование. – Pixelchemist

+0

Итак, даже если у меня нет объекта класса b, созданного в моем главном коде, запускается конструктор по умолчанию для класса B? – user2076774

Смежные вопросы