Когда я должен использовать списки инициализатора для инициализации участников класса C++?

Вы могли бы быть в состоянии использовать IronRuby для этого.

Иначе я предложил бы, чтобы у Вас был каталог, куда Вы помещаете предварительно скомпилированные блоки. Тогда Вы могли иметь ссылку в DB к блоку и классу, и использовать отражение для загрузки правильных сборок во времени выполнения.

, Если Вы действительно хотите скомпилировать во времени выполнения, Вы могли бы использовать CodeDOM, тогда Вы могли использовать отражение для загрузки динамического блока. статья документации Microsoft, которая могла бы помочь .

5
задан Shog9 18 August 2010 в 23:33
поделиться

7 ответов

m_somemap

  1. Необязательно.
  2. Что вы получите, если опустите его: пустой std :: map , т. е. действительный экземпляр этой карты, в которой нет элементов.

m_somebool

  1. Вы должны инициализировать его значением true или false , если вы хотите, чтобы у него было известное значение. Логические значения - это «простые старые типы данных», и они не имеют концепции конструктора. Более того, язык C ++ не определяет значения по умолчанию для неявно инициализированных логических значений.
  2. Что вы получите, если опустите его: логический член с неопределенным значением. Вы не должны делать этого, а затем использовать его значение. По этой причине настоятельно рекомендуется инициализировать все значения этого типа.

m_someint

  1. Вы должны инициализировать его некоторым целочисленным значением, если вы хотите, чтобы оно имело известное значение. Целые числа - это «простые старые типы данных», и они не имеют концепции конструктора. Более того, язык C ++ не определяет значения по умолчанию для неявно инициализированных целых чисел.
  2. Что вы получите, если его опустите: член типа int с неопределенным значением. Вы не должны делать этого, а затем использовать его значение. В связи с этим настоятельно рекомендуется инициализировать все значения этого типа.
12
ответ дан 18 December 2019 в 09:08
поделиться

На самом деле нет необходимости делать это.
Конструктор по умолчанию сделает это автоматически.

Но иногда, делая его явным, он действует как своего рода документация:

class X
{
    std::map<string,string>  data;
    Y                        somePropertyOfdata;

    X()
      :data()                    // Technically not needed
      ,somePropertyOfdata(data)  // But it documents that data is finished construction
    {}                           // before it is used here.
};

Правило C ++ состоит в том, что, если вы явно не инициализируете данные POD, они не определены, в то время как другие классы имеют конструктор по умолчанию, вызываемый автоматически (даже если это явно не сделано программистом).

Но говоря это. Примите во внимание следующее:

template<typename T>
class Z
{
     T  data;   
     Z()
        :data()    // Technicall not need as default constructor will
                   // always be called for classes.
                   // But doing this will initialize POD data correctly
                   // if T is a basic POD type. 
     {}
};

Здесь вы ожидаете, что данные будут инициализированы по умолчанию.
Технически POD не имеет конструкторов, поэтому, если бы T был int, ожидали ли вы, что он что-нибудь сделает? Поскольку он был явно инициализирован, он установлен в 0 или эквивалент для типов POD.

Для редактирования:

class A
{
    std::map<string,string>   m_someMap;
    int                       m_someint;
    bool                      m_somebool;
   public:
    A::A()
       : m_someMap()      // Class will always be initialised (so optional)
       , m_someint(0)     // without this POD will be undefined
       , m_somebool(false)// without this POD will be undefined
    {}
};
4
ответ дан 18 December 2019 в 09:08
поделиться

Как отмечали другие: это не обязательно, но более или менее вопрос стиля. Плюс: он показывает, что вы явно хотите использовать конструктор по умолчанию, и делает ваш код более подробным. Обратная сторона: если у вас более одного ctor, может быть сложно поддерживать изменения во всех из них, и иногда вы добавляете членов класса и забываете добавить их в список инициализаторов ctors, и это выглядит несогласованным.

1
ответ дан 18 December 2019 в 09:08
поделиться

Просто чтобы прояснить, что происходит (относительно вашего второго вопроса)

std :: map m_someMap создает стек переменная называется m_someMap, и для нее вызывается конструктор по умолчанию. Правило C ++ для всех ваших объектов:

T varName;

где T - это тип, varName создается по умолчанию.

T* varName;

должно быть явно присвоено NULL (или 0) - или nullptr в новом стандарте.

0
ответ дан 18 December 2019 в 09:08
поделиться
A::A() : m_someMap()

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

Если у вас есть конструктор, такой как этот:

X() : y(z) {
 w = 42;
}

, то при X происходит следующее. вызывается конструктор:

  • Сначала инициализируются все члены: для y мы явно говорим, что хотим вызвать конструктор, который принимает в качестве аргумента z . Для w то, что происходит, зависит от типа w . Если w является типом POD (то есть в основном C-совместимым типом: без наследования, без конструкторов или деструкторов, все члены являются общедоступными и все члены также являются типами POD), то это не инициализирован. Его начальное значение - это мусор, обнаруженный по этому адресу памяти. Если w не является типом POD, то вызывается его конструктор по умолчанию (типы, не относящиеся к POD, всегда инициализируются при построении).
  • После создания обоих членов мы затем вызывают оператор присваивания, чтобы присвоить 42 w .

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

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

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

  • Что, если w относится к типу, не имеющему конструктора по умолчанию? Тогда это не будет компилироваться. Затем он должен быть явно инициализирован после : , например y is.
  • Что, если эта последовательность вызова обоих конструктора по умолчанию а оператор присваивания работает излишне медленно? Возможно, было бы намного эффективнее просто вызвать правильный конструктор для начала.

Короче говоря, поскольку m_someMap не является типом POD, нам, строго говоря, не нужно делать : m_someMap () . В любом случае он был бы построен по умолчанию. Но если бы это был тип POD или если бы мы хотели вызвать другой конструктор, отличный от конструктора по умолчанию, то нам пришлось бы это сделать.

1
ответ дан 18 December 2019 в 09:08
поделиться

Когда вы создаете объект на C ++, конструктор выполняет следующую последовательность:

  1. Вызов конструкторов всех родительских виртуальных классов во всем дереве классов (в произвольном порядке)
  2. Вызов конструкторов всех непосредственно наследуемых родительских классов в порядке объявления
  3. Вызов конструкторов всех переменных-членов в порядке объявления

Есть еще несколько особенностей, чем это, и некоторые компиляторы позволяют принудительно несколько вещей вне этого конкретного порядка, но это общая идея. Для каждого из этих вызовов конструктора вы можете указать аргументы конструктора, и в этом случае C ++ вызовет конструктор, как указано, или вы можете оставить его в покое, и C ++ попытается вызвать конструктор по умолчанию. Конструктор по умолчанию - это просто тот, который не принимает аргументов.

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

Когда дело доходит до встроенных типов, таких как float или int ], конструктор по умолчанию вообще ничего не делает, и поэтому переменная будет иметь значение по умолчанию, равное тому, что осталось в части памяти. Все встроенные типы также имеют конструктор копирования, поэтому вы можете инициализировать их, передав их начальное значение в качестве единственного аргумента конструктору переменной.

0
ответ дан 18 December 2019 в 09:08
поделиться

Чтобы прояснить проблему значений по умолчанию:

В C ++ нет концепции имплицитности некоторых типов по ссылке. Если что-то явно не объявлено как указатель, оно не может принимать нулевое значение. Это означает, что каждый класс будет иметь конструктор по умолчанию для построения начального значения, если параметры конструктора не указаны. Если конструктор по умолчанию не объявлен, компилятор сгенерирует его для вас. Кроме того, всякий раз, когда класс содержит члены классифицированных типов, эти члены будут неявно инициализированы через их собственные конструкторы по умолчанию при создании объекта , если вы не используете синтаксис двоеточия для явного вызова другого конструктора.

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

0
ответ дан 18 December 2019 в 09:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: