Инициализация производных классов в c ++ - PullRequest
2 голосов
/ 30 декабря 2011
//This program is taken from http://www.learncpp.com/cpp-tutorial/114-constructors-and-initialization-of-derived-classes/
#include <iostream>
using namespace std;

class A
{
public:
    A(int nValue)
    {
        cout << "A: " << nValue << endl;
    }
};

class B: public A
{
public:
    B(int nValue, double dValue)
    : A(nValue)
    {
        cout << "B: " << dValue << endl;
    }
};

int main()
{
    B bClass(5, 4.3);

    return 0;
}

Когда я запускаю это:

$g++ inherit.cpp -o inherit
$ ./inherit 
A: 5
B: 4.3

, что ожидается.Но когда я изменяю class B на это:

class B: public A
{
int something;
public:
    B(int nValue, double dValue)
    : something(nValue), A(nValue)
    {
        cout << "B: " << dValue << endl;
    cout << "B.something: " << something << endl;
    }
};

, получается:

$ ./inherit 
A: 5
B: 4.3
B.something: 5

Мой вопрос:

Когда компилятор просматривает список инициализации B,он только ищет конструктор базового класса и переходит к нему, а не выполняет другие операторы (something(nValue))или он выполняет все операторы до тех пор, пока не найдет конструктор BaseClass и просто не выполнит тело конструктора, пока не выполнится выполнение конструктора базового класса?Другими словами, будет ли установлено значение B.something равным nValue при первом обращении к оператору something(nValue) или оно останется неинициализированным до вызова A (nValue)?

Ответы [ 3 ]

9 голосов
/ 30 декабря 2011

Все подобъекты и нестатические объекты-члены экземпляра класса инициализируются в фиксированном порядке, а именно в порядке их объявления (а именно: сначала все подобъекты в порядке (например, A, B, C для class Foo : A, B, C), затем нестатические объекты-члены).

Порядок, в котором вы перечисляете инициализаторы в списке инициализаторов, не влияет на это поведение; тем не менее, вы всегда должны писать IL в правильном порядке, чтобы избежать неожиданностей и сделать ваш код как можно более легким для чтения.

Как правило, следует избегать зависимости одного инициализатора объекта от другого объекта, но иногда это может быть необходимо. Если возможно, просто используйте аргумент конструктора. Пример:

struct Foo {
   int a;
   int b;
   Foo(int a_, int b_) : a(a_), b(a) { }   // not so good, depends on order!
   Foo(int a_, int b_) : a(a_), b(a_) { }  // better, always works
};

Теперь представьте, что вместо этого у нас есть struct Foo : Bar, и у вас может возникнуть желание написать инициализатор для Foo как a(a_), b(a), Bar(a, b). Это было бы катастрофой. Запись IL по порядку делает это невозможным: Bar(a_, b_), a(a_), b(a_).

3 голосов
/ 30 декабря 2011

Порядок создания (и уничтожения) подобъекта только определяет порядок, в котором объявлены базовые классы и члены. Порядок в списке инициализатора игнорируется. Использование другого порядка подобъекта в списке инициализатора может запутать вас и других читателей кода: не делайте этого. Некоторые компиляторы предупреждают об этом. Об этом также говорится в «Эффективном C ++» Скотта Мейера (настоятельно рекомендуется к прочтению; я считаю это обязательным чтением для любого профессионального программиста C ++).

0 голосов
/ 30 декабря 2011

Я запустил программу inherit в gdb, и оказалось, что что-то остается неинициализированным до тех пор, пока A (nValue) не завершит выполнение.

Breakpoint 1, main () at inherit.cpp:27
27      B bClass(5, 4.3);
(gdb) nexti
0x08048693  27      B bClass(5, 4.3);
(gdb) s
B::B (this=0xbffff2dc, nValue=5, dValue=4.2999999999999998) at inherit.cpp:18
18      : something(nValue), A(nValue)
(gdb) p something
$2 = 3751924
(gdb) nexti
0x08048760  18      : something(nValue), A(nValue)
(gdb) p something
$3 = 3751924
(gdb) nexti
0x08048764  18      : something(nValue), A(nValue)
(gdb) p something
$4 = 3751924
(gdb) nexti
0x08048767  18      : something(nValue), A(nValue)
(gdb) p something
$5 = 3751924
(gdb) nexti
0x0804876a  18      : something(nValue), A(nValue)
(gdb) p something
$6 = 3751924
(gdb) nexti
A: 5 //A(nValue) HAS FINISHED EXECUTION AND something is still uninitialized
0x0804876f  18      : something(nValue), A(nValue)
(gdb) p something
$7 = 3751924
(gdb) nexti
0x08048772  18      : something(nValue), A(nValue)
(gdb) p something
$8 = 3751924
(gdb) nexti
0x08048775  18      : something(nValue), A(nValue)
(gdb) p something
$9 = 3751924
(gdb) nexti
20          cout << "B: " << dValue << endl;
(gdb) p something
$10 = 5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...