Список инициализации конструктора начинается с двоеточия, за которым следует разделённый запятыми список членов данных, каждый член данных сопровождается инициализатором в круглых скобках. Например:

class CExample {
public:
    int a;
    float b;
    //构造函数初始化列表
    CExample(): a(0),b(8.8)
    {}
    //构造函数内部赋值
    CExample()
    {
        a=0;
        b=8.8;
    }
};

В приведённом выше примере результаты двух конструкторов одинаковы. Приведённый выше конструктор (тот, который использует список инициализации) явно инициализирует члены класса; тогда как конструктор, не использующий список инициализации, присваивает значения членам класса без явной инициализации.

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

  • 1. Тип члена —класс без конструктора по умолчанию. Если явный инициализатор не предоставлен, компилятор неявно использует конструктор по умолчанию для этого типа члена. Если у класса нет конструктора по умолчанию, попытка компилятора использовать конструктор по умолчанию завершится неудачей.члены const
  • 2.члены constиличлены ссылочного типа. Поскольку объекты const или ссылочные типы можно только инициализировать, но не присваивать им значения.

Что означает инициализировать члены данных в отличие от присваивания значений членам данных? В чём разница?

Сначала классифицируем члены данных по типу и объясним каждый случай:

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

Примечания:

Порядок инициализации членов в списке инициализации:

C++ инициализирует члены класса в порядке их объявления, а не в порядке их появления в списке инициализации.

class CMyClass {
    CMyClass(int x, int y);
    int m_x;
    int m_y;
};

CMyClass::CMyClass(int x, int y) : m_y(y), m_x(m_y)
{
};

Вы можете подумать, что приведённый выше код сначала выполнит m_y=I, затем m_x=m_y, и в конце они будут иметь одинаковое значение. Но компилятор инициализирует m_x первым, затем m_y, потому что они объявлены в таком порядке. В результате m_x будет иметь непредсказуемое значение. Есть два способа избежать этого: первый — всегда объявлять члены в том порядке, в котором вы хотите их инициализировать; второй — если вы решили использовать список инициализации, всегда перечисляйте члены в порядке их объявления. Это поможет устранить путаницу.

Исходный адрес: http://www.cnblogs.com/BlueTzar/articles/1223169.html