Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по С++ глава 3.doc
Скачиваний:
6
Добавлен:
05.11.2018
Размер:
187.9 Кб
Скачать

Int Left;

int Top;

Int Right;

Int Bottom;

public:

// конструктор по умолчанию: CRectangle()

CRectangle()

{

Left = Top = Right = Bottom = 0;

}

// конструктор с параметрами:

CRectangle (int L, int T, int R, int 8)

{

SetCoord (L, T, R, B);

}

// определения других функций-членов ...

};

Следующий код демонстрирует использование перегруженного конструктора CRectangle.

void main()

{

// создание объекта с использованием конструктора по умолчанию:

CRectangle Rectl;

// создание объекта с указанием начальных значений:

CRectangle Rect2 (25, 25, 100, 100);

//...

}

Примечание

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

Инициализация переменных-членов в конструкторах

При определении класса запрещается инициализировать переменные-члены. Так, следующее определение класса содержит ошибки.

class С

{

private:

int N = 0; //ОШИБКА

const int CInt = 5; //ОШИБКА

int &RInt = N; //ОШИБКА

// ...

};

Инициализация переменных внутри определения класса бессмысленна, потому что определение класса задает всего лишь тип каждой из переменных-членов, но не резервирует для них реальную область памяти. Скорее всего, при написании программы требуется инициализировать переменные-члены каждый раз при описании экземпляра класса. Следовательно, целесообразно инициализировать переменные внутри конструктора класса. Конструктор класса CRectangle инициализирует переменные-члены, используя выражение присваивания. Однако определенным типам данных, в частности, константам и ссылкам, не могут быть присвоены значения. Чтобы эта проблема не возникала, в языке C++ предусмотрено специальное свойство конструктора, называемое списком инициализации, который позволяет инициализировать одну или более переменных, а не присваивать им значения.

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

class С

{

private:

int N;

const int CInt;

int &RInt;

// ...

public:

С (int Parm) : N (Farm), CInt (5), RInt (N)

{

// код конструктора ...

}

// ...

};

Следующее определение создает объект, демонстрирующий применение списка инициализации, где переменные N и CInt инициализированы значениями 0 и 5, а переменная-член RInt – как ссылка на переменную N:

С CObject (0);

Константные объекты и функции-члены

Как показано в гл. 2, добавление спецификатора const к определению переменной означает невозможность изменения ее значения. Аналогично, добавление спецификатора const в определение объекта класса означает, что нельзя изменять значения переменных, принадлежащих этому классу. Рассмотрим, например, класс

class CTest

{

public:

int A;

int B;

CTest (int AVal, int BVal);

{

A = AVal;

В = BVal;

}

}

Оператор создает объект этого класса и инициализирует обе переменные-члены

const CTest Test (1, 2} ;

Это первая и последняя возможность присвоить значения таким переменным. Из-за спецификатора const недопустимо присваивание

Test.А =3; // ОШИБКА: нельзя изменять переменные-члены

//Объекта типа const

Существуют и другие варианты объявления объекта с использованием спецификатора const. Чтобы продемонстрировать их, рассмотрим объявление объекта класса CRectangle, приведенного в этой главе.

const CRectangle Rect (5, 5, 25, 25) ;

Хотя функция-член GetCoord класса CRectangle не изменяет никаких переменных-членов, компилятор не позволит программе вызвать ее для объекта с атрибутом const.

int L, Т, R, В;

Rect.GetCoord (&L, &T, &R, &B); //ошибка

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

Чтобы иметь возможность вызова функции GetCoord для объекта типа const, следует включить спецификатор const в определение функции.

class CRectangle

{

//...

void GetCoord (int *L6 int *T6 int *R, int *B) const

{

*L = Left;

*T = Top;

*R = Right;

*B = Bottom;

}

// ...

};

Спецификатор const в определении функции GetCoord означает, что функция не может изменять переменные-члены. Если она пытается это сделать, компилятор будет генерировать ошибку при компиляции исходного кода. Функцию GetCoord сейчас можно вызвать для объекта типа const класса CRectangle.

const CRectangle Rect (5, 5, 25, 25);

int L, T, R, B;

Rect.GetCoord (&L, &T, &R, &B); //допустимо: функция GetCoord

// объявлена как const

Кроме того, можно функцию-член Draw объявить как const, так как она не изменяет значений переменных. Очевидно, имеет смысл добавлять спецификатор const ко всем функциям-членам, которые не модифицируют поля класса, чтобы пользователь мог свободно вызывать такие функции для объектов типа const. Конечно, функцию, подобную CRectangle:: SetCoord, нельзя объявить как const.

Инициализация объектов-членов класса. Можно определить переменную, являющуюся объектом другого класса, т. е. можно встроить объект одного класса в объект другого. Такие переменные называют объектами-членами или встроенными объектами. Его можно инициализировать, передавая требуемые параметры конструктору, помещенному в список инициализации конструктора класса, содержащего объект-член. Например, класс CContainer в следующем примере содержит объект-член класса CEmbedded, инициализируемый в конструкторе класса CContainer.

class CEmbedded

{

//...

public:

CEmbedded (int Parml, int Parm2)

{

// ...

}

// ...

};

class CContainer

{

private:

CEmbedded Embedded;

public:

CContainer (int PI, int P2, int P3) : Embedded (PI, P2)

{

// код конструктора ...

}

// ...

};

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

Примечание

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