void Screen::dummy_fcn(pos height) {

 cursor = width * ::height; // который height? Глобальный

}

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

Поиск имен распространяется по всему файлу, где они были применены

Когда член класса определен вне определения класса, третий этап поиска его имени происходит не только в объявлениях глобальной области видимости, которые расположены непосредственно перед определением класса Screen, но и распространяется на остальные объявления в глобальной области видимости. Рассмотрим пример.

int height; // определяет имя, впоследствии используемое в Screen

class Screen {

public:

 typedef std::string::size_type pos;

 void setHeight(pos);

 pos height = 0; // скрывает объявление height из внешней

                 // области видимости

};

Screen::pos verify(Screen::pos);

void Screen::setHeight(pos var) {

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

 // height: относится к члену класса

 // verify: относится к глобальной функции

 height = verify(var);

}

Обратите внимание, что объявление глобальной функции verify() не видимо перед определением класса Screen. Но третий этап поиска имени включает область видимости, в которой присутствует определение члена класса. В данном примере объявление функции verify() расположено перед определением функции setHeight(), a потому может использоваться.

Упражнения раздела 7.4.1

Упражнение 7.34. Что произойдет, если поместить определение типа pos в последнюю строку класса Screen?

Упражнение 7.35. Объясните код, приведенный ниже. Укажите, какое из определений, Type или initVal, будет использовано для каждого из имен. Если здесь есть ошибки, найдите и исправьте их.

typedef string Type;

Type initVal();

class Exercise {

public:

 typedef double Type;

 Type setVal(Type);

 Type initVal();

private:

 int val;

};

Type Exercise::setVal(Type parm) {

 val = parm + initVal();

 return val;

}

<p>7.5. Снова о конструкторах</p>

Конструкторы — ключевая часть любого класса С++. Основы конструкторов рассматривались в разделе 7.1.4, а в этом разделе описаны некоторые из дополнительных возможностей конструкторов и подробности материала, приведенного ранее.

<p><image l:href="#reader.png"/>7.5.1. Список инициализации конструктора</p>

Когда определяются переменные, они, как правило, инициализируются сразу, а не определяются и присваиваются впоследствии:

string foo = "Hello World!"; // определить и инициализировать

string bar;           // инициализация по умолчанию пустой строкой

bar = "Hello World!"; // присвоение нового значения переменной bar

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

// допустимый, но не самый лучший способ создания конструктора

// класса Sales_data: нет инициализатора конструктора

Sales_data::Sales_data(const string &s,

                       unsigned cnt, double price) {

 bookNo = s;

 units_sold = cnt;

 revenue = cnt * price;

}

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

Иногда применение списка инициализации конструктора неизбежно

Зачастую, но не всегда, можно игнорировать различие между инициализацией и присвоением значения переменной-члену. Переменные-члены, являющиеся константой или ссылкой, должны быть инициализированы. Аналогично члены класса, для типа которых не определен стандартный конструктор, также следует инициализировать. Например:

class ConstRef {

Перейти на страницу:

Похожие книги