2013-10-25 3 views
0

Я только что прочитал в this answer, что если у вас есть следующий кодКаков порядок инициализации в классе?

class Base 
{ 
    public Base() 
    { 

    } 
} 

class One : Base 
{ 
    string test = "text"; 
} 

class Two : Base 
{ 
    string test; 
    public Two() 
    { 
     test = "text"; 
    } 
} 

Для класса одним из initializaton One.test будет initalized до того Base :: Base называется. Но Two.test будет инициализирован после вызова Base :: Base.

Я предполагаю, что это потому, что в обоих случаях

  1. поля < - это включает в себя One.test
  2. Base :: Base()
  3. Один :: Один (или) Два :: Two() < - который инициализирует Two.test

Я думаю, что я помню, что списки инициализации находятся непосредственно перед конструктором. Так порядок инициализации затем:

  1. поля
  2. базовый список инициализатор
  3. базовый конструктор
  4. собственный список инициализатор
  5. собственный конструктор

И где же поля базы заходи? Все ли поля инициализируются первым, когда выделена память или непосредственно перед списком инициализации текущего базового класса?

И есть ли другие шаги в списке, о которых вы можете думать?

Буду признателен, если кто-то может дать хороший обзор.

+2

Итак, как вы подключения C# ответ с C++? – 0x499602D2

+0

Полностью пропустил это. Ну, мне все равно хотелось бы знать, как это работает, как на C++. – Sarien

+0

Написанный код недействителен в C++. – deepmax

ответ

2

C инициализация ++ происходит в следующем порядке:

  1. базовых классов, слева направо
  2. переменных-членов, в том порядке, в котором они объявили

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

Поэтому, когда компилятор встречает:

Two two; 

Во-первых, Two::Two начинает выполнение, начиная со списком инициализатора. Все базы инициализируются через список инициализации, даже если вы не написали или не оставили инициализацию базового класса. Таким образом, код, который на самом деле работает выглядит примерно так:

Two::Two 
: 
    One(), 
    test() 
{ 
    test = "text"; 
} 

Список инициализатор выполняется , прежде чем тело конструктора. Поэтому One полностью сконструирован до того, как тело Two::Two начнет выполнение.

В свою очередь, One выглядит следующим образом:

One::One() 
: 
    Base() 
{ 
    string test = "test"; 
} 

И Base пусто:

Base::Base() 
{ 
} 

Так что же происходит, когда Two two; выполняется это:

  1. Base построен.
  2. One построен
  3. Автоматическая переменная test построена, инициализируются и уничтожаются в контексте One::One
  4. Two::test по умолчанию инициализируется
  5. Two::test присваивается значение "текст"

Обратите внимание, что некоторые из них, особенно этапы 4 & 5 могут быть оптимизированы компилятором, если он считает, что это безопасно.

+0

@LokiAstari: О, кричит. Я думал, что это выглядит так: 'class Two: public One' и' class One: public Base' –

+0

Случай «Один» не так точно изображен в этом ответе. Нет локальной переменной 'test', а не переменной-членом с значением инициализатора. Это преобразуется компилятором в: 'One(): Base(), test (" test ") {}' –

2

Для класса Один инициализируется инициализация initializaton One.test до вызова Base :: Base. Но Two.test будет инициализирован после вызова Base :: Base.

No. Основания инициализированы до любой участник.

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

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

В случае Two есть одна деталь, которая, вероятно, имеет значение, и я не уверен, что вы знаете, член testявляется инициализируются в списке инициализаторе Two, перед тем входом в тело конструктора, и то он назначается.

+0

Инициализация базы включает в себя рекурсивные базы, список инициализации, члены и конструктор, правильно? – Sarien

+0

@Sarien: Исправлена ​​полная инициализация, включая базы, элементы и тело конструктора. –

1

Другие ответили на вопрос.
Но следующая демо может быть полезна.

#include <iostream> 
class String 
{ 
    public: 
     String(char const* d)    {std::cout << "String Constructor: " << d << "\n";} 
     String()       {std::cout << "String Constructor: Default\n";} 
     String(String const& rhs)   {std::cout << "String Constructor: Copy\n";} 
     String& operator=(String const& rhs){std::cout << "String Assignment\n";} 
     ~String()       {std::cout << "String Destructor\n";} 
}; 

class Base 
{ 
    public: Base() 
    { 
     std::cout << "Base::Base()\n"; 
    } 
}; 

class One : Base 
{ 
    String test = "text"; 
}; 

class Two : Base 
{ 
    String test; 
    public: Two() 
    { 
     std::cout << "Two::Two\n"; 
     test = "text"; 
    } 
}; 

int main() 
{ 
    std::cout << "Trying One\n"; 
    One  one; 

    std::cout << "==========\n\n\n"; 
    std::cout << "Trying Two\n"; 
    Two  two; 

    std::cout << "==========\n\n\n"; 
    std::cout << "Trying Base\n"; 
    Base b; 
} 

Результат этого:

> ./a.out 
Trying One     // Outside the class about to start 
Base::Base()     // One: Calls the base constructor first Base 
String Constructor: text  // One: Constructs its members. 
========== 


Trying Two     // Outside the class about to start 
Base::Base()     // Two: Calls the base construtor first 
String Constructor: Default // Two: Constructs its members next 
Two::Two      // Two: Now entering the body of the constructor 
String Constructor: text  //  Builds a string 
String Assignment    //  Calls the assignment constructor. 
String Destructor    //  Temporary destroyed. 
==========     // 


Trying Base 
Base::Base() 
String Destructor    // Destroys the string in Two 
String Destructor    // Destroys the string in One 
Смежные вопросы