Что делает двоеточие после имени конструктора С++?

Что делает оператор двоеточия ( ":" ) в этом конструкторе? Это эквивалентно MyClass(m_classID = -1, m_userdata = 0);?

class MyClass {
public:

    MyClass() : m_classID(-1), m_userdata(0) { 
    }

    int m_classID;
    void *m_userdata;
};
71
задан spencewah 13 авг. '09 в 18:22
источник поделиться

9 ответов

Это список инициализации и является частью реализации конструктора.

Подпись конструктора:

MyClass();

Это означает, что конструктор можно вызвать без параметров. Это делает его конструктором по умолчанию, т.е. Тем, который будет вызываться по умолчанию при написании MyClass someObject;.

Часть : m_classID(-1), m_userdata(0) называется списком инициализации. Это способ инициализировать некоторые поля вашего объекта (все они, если хотите) со значениями по вашему выбору, вместо того, чтобы оставлять их как undefined.

После выполнения списка инициализации выполняется создание тела конструктора (который окажется пустым в вашем примере). Внутри вы могли бы выполнять больше назначений, но после того, как вы ввели его, все поля уже были инициализированы - либо случайными, неуказанными значениями, либо теми, которые вы выбрали в списке инициализации. Это означает, что присваивания, которые вы выполняете в теле конструктора, не будут инициализированы, а изменения значений.

78
ответ дан Daniel Daranas 13 авг. '09 в 18:26
источник поделиться

Это список инициализации.

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

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

Список инициализации необходим, если одно из полей является ссылкой, потому что ссылка никогда не может быть нулевой, даже в короткие промежутки времени между конструкцией объекта и телом конструктора. Ниже приведена ошибка C2758: "MyClass:: member_": должна быть инициализирована в списке инициализатора основы/члена элемента

class MyClass {
public :
    MyClass(std::string& arg) {
        member_ = arg;
    }
    std::string& member_;
};

Единственный правильный способ:

class MyClass {
public :
    MyClass(std::string& arg) 
        : member_(arg) 
    {
    }
    std::string& member_;
};
37
ответ дан Asik 13 авг. '09 в 18:37
источник поделиться

Он обозначает начало списка инициализации, который предназначен для инициализации переменных-членов вашего объекта.

Что касается: MyClass(m_classID = -1, m_userdata = 0);

Это объявляет конструктор, который может принимать аргументы (поэтому я мог бы создать MyClass с помощью MyClass m = MyClass(3, 4), что приведет к тому, что m_classID будет равно 3, а m_userdata будет 4). Если бы я не передавал аргументы конструктору MyClass, это привело бы к созданию эквивалентного объекта для версии с списком инициализации.

2
ответ дан Dominic Rodger 13 авг. '09 в 18:25
источник поделиться

Он сигнализирует о начале списка инициализаторов.

Также он не эквивалентен MyClass (m_classId = -1, m_userData = 0). Это попытка определить конструктор с двумя параметрами, которые имеют значения по умолчанию. Однако значения не имеют типов и не должны компилироваться вообще.

2
ответ дан JaredPar 13 авг. '09 в 18:27
источник поделиться

Это не совсем оператор. Это часть синтаксиса для конструктора.

Что он говорит, так это то, что после него будет список переменных-членов и их начальные значения.

Константные члены должны быть инициализированы таким образом. Неконстанты также могут быть инициализированы здесь, если это можно сделать с помощью одного выражения. Если для инициализации элемента требуется больше кода, чем для этого, вы должны поставить фактический код между {}, чтобы сделать это.

Многим людям нравится вносить почти весь свой код конструктора в список инициализаторов. У меня есть один сотрудник, который регулярно пишет классы с несколькими экранами инициаторов, а затем помещает "{}" для кода конструктора.

1
ответ дан T.E.D. 13 авг. '09 в 18:28
источник поделиться

Это список инициализации. В вашем примере это скорее нечто вроде этого (что-то вроде этого - не означает, что это эквивалентно во всех случаях):


class MyClass {

public:

    MyClass(){
         m_classID = -1;
         m_userdata = 0;
    }

    int m_classID;
    void *m_userdata;

};
1
ответ дан Marcin Deptuła 13 авг. '09 в 18:26
источник поделиться

Это называется списком инициализации членов. Он используется для вызова конструкторов суперкласса и дает вашим переменным-членам начальное значение в момент их создания.

В этом случае он инициализирует от m_classID до -1 и m_userData значение NULL.

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

1
ответ дан JohnMcG 13 авг. '09 в 18:27
источник поделиться

Это начало списка инициализации, который устанавливает переменные-члены во время построения объекта. Ваш пример "MyClass (m_classID = -1, m_userdata = 0); невозможно, поскольку вы не определили правильный конструктор, и в любом случае вы не сможете получить доступ к переменным-членам в списке параметров... у вас может быть что-то вроде:

MyClass( int classId = -1, void* userData = 0 ) : m_classID(classId), m_userdata(userData) {}

Список инициализации считается лучше, чем:

MyClass( int classId = -1, void* userData = 0 ) {
    m_classID = classId;
    m_userdata = userData;
}

Google для получения дополнительной информации.

1
ответ дан Patrick 13 авг. '09 в 18:29
источник поделиться

В этом случае: Yes, ist эквивалентен, поскольку речь идет только о примитивных типах.

Если члены являются классами (structs), вы должны предпочесть список инициализации. Это происходит потому, что в противном случае объекты по умолчанию сконструированы и затем назначены.

0
ответ дан SebastianK 13 авг. '09 в 18:25
источник поделиться

Другие вопросы по меткам