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

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

class MyClass {
public:

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

    int m_classID;
    void *m_userdata;
};

person spencewah    schedule 13.08.2009    source источник


Ответы (9)


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

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

MyClass();

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

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

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

person Daniel Daranas    schedule 13.08.2009

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

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

Таким образом, в случае примитивных типов, таких как 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_;
};
person Asik    schedule 13.08.2009
comment
Часто ошибочно полагают, что если у вас есть ссылочный член, вы должны определить конструктор со списком инициализаторов конструктора. Но это не совсем так. Простой MyClass m = { arg }; тоже подойдет. - person Johannes Schaub - litb; 13.08.2009
comment
litb: но тогда вам более или менее необходимо использовать m = {arg}; разве ты? На мой взгляд, очень желательно иметь возможность использовать MyClass m (ref). - person Skurmedel; 13.08.2009
comment
@Skurmedel, я согласен. Но это, конечно, не означает, что это единственный способ сделать это. - person Johannes Schaub - litb; 13.08.2009
comment
Верно; в любом случае я не знал, что вы можете это сделать, так что хороший комментарий :). - person Skurmedel; 13.08.2009
comment
Спасибо, я не знал об этом. Хотя быстрый поиск в MSDN показал, что этот синтаксис имеет очень ограниченное применение: см. Ошибку компилятора C2552. msdn.microsoft.com/en-us/library/0s6730bb (VS.80) .aspx - person Asik; 13.08.2009
comment
если вы присваиваете им значение в теле конструктора, вы вызываете конструктор копирования. Нет, это не так. Оператор присваивания копии отличается от конструктора копирования. - person Ben Voigt; 15.02.2015
comment
Это неверный ответ. Я голосую за его удаление. Каждый должен -1 это. По-видимому, это вызывает недоумение у новичков (stackoverflow.com/questions/28529416/). - person thang; 15.02.2015
comment
@thang Я исправил ответ на основании вашего отзыва. - person Asik; 26.04.2016

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

As to: MyClass(m_classID = -1, m_userdata = 0);

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

person Dominic Rodger    schedule 13.08.2009

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

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

person JaredPar    schedule 13.08.2009

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


class MyClass {

public:

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

    int m_classID;
    void *m_userdata;

};
person Marcin Deptuła    schedule 13.08.2009

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

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

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

person JohnMcG    schedule 13.08.2009
comment
Также иногда необходимо использовать список инициализации членов. Если у вас есть переменная-член, которая является ссылкой, вы должны установить ее с помощью списка инициализации элементов. - person Skurmedel; 13.08.2009

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

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

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

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

person T.E.D.    schedule 13.08.2009

Это начало списка инициализаторов, который устанавливает переменные-члены во время создания объекта. Ваш пример «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 для получения дополнительной информации.

person Patrick    schedule 13.08.2009

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

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

person SebastianK    schedule 13.08.2009