Каков порядок инициализации у учеников?

0

Я просто прочитал в этом ответе, что если у вас есть следующий код

class Base
{
    public Base()
    {

    }
}

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

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

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

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

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

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

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

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

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

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

  • 2
    Итак, как вы соединяете ответ C # с C ++?
  • 0
    Совершенно пропустил это. Ну, я все еще хотел бы знать, как это работает в C ++.
Показать ещё 2 комментария
Теги:
initialization
initialization-list

3 ответа

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 присваивается значение "text"

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

  • 0
    @LokiAstari: Ой, упс. Я думал, что это выглядело так: class Two : public One и class One : public Base
  • 0
    Случай One не совсем так, как изображено в этом ответе. Нет test локальной переменной, а есть переменная-член со значением инициализатора. Это переводится компилятором в: One() : Base(), test("test") {}
2

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

Нет. Базы инициализируются перед любым членом.

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

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

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

  • 0
    Инициализация базы включает в себя рекурсивные базы, список инициализации, члены и конструктор, верно?
  • 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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню