Освой самостоятельно С++ за 21 день.
Шрифт:
34: {
35: if( x < Window::MAX_X && x > 0 )
36: Pane::x = x ;
37: if( y< Window::MAX_Y && y > 0 )
38: Pane::y = y ;
39: }
40: void Window::Pane::show
41: {
42: std::cout << "x " << Pane::x;
43: std::cout << " y " << Pane::y << std::endl;
44: }
45:
46: int main
47: {
48: Window::Pane pane;
49:
50: pane.move( 20, 20 );
51: pane.show;
52:
53: return 0;
54: }
Результат:
x 20 y 20
Анализ:
Статическая переменная-член cnt, объявленная в строке 16 внутри класса Pane, определяется как обычно. Но при определении функции-члена Pane: :size и обращениях к переменным-членам MAX_X и MAX_Y в строках 26-32 используется явное указание пространства имен. Дело в том, что статическая переменная-член определяется внутри класса Pane, а определения других функций-членов (это же справедливо для функции Pane::move) происходят как за пределами класса, так и вне тела пространства имен. Без явного указания пространства имен компилятор покажет сообщение об ошибке.
Обратите внимание также на то, что внутри определений функций-членов обращение к объявленным переменным-членам класса происходит с явным указанием имени класса: Pane::x и Pane::y. Зачем это делается? Дело в том, что у вас возникли бы проблемы, если функция Pane::move определялась бы следующим образом:
void Window::Pane::move( int x, int у )
{
if( x < Window::MAX_X && x > 0 )
x = x;
if( у < Window::MAX_Y && у > 0 )
У = У;
Platform::move( x, у );
}
Ну что, догадались, в чем проблема? Опасность состоит в том, что компилятор в этом выражении никаких ошибок не заметит.
Источник проблемы заключается в аргументах функции. Аргументы x и у скроют закрытые переменные-члены x и у, объявленные в классе Pane, поэтому вместо присвоения значений аргументов переменным-членам произойдет присвоение этих значений самим себе. Чтобы исправить эту ошибку, необходимо явно указать переменные-члены класса:
Pane::x = x;
Pane::y = у;
Ключевое слово using
Ключевое слово using может использоваться и как оператор, и в качестве спецификатора при объявлении членов пространства имен, но синтаксис использования using при этом меняется.
Использование using как оператора
С помощью ключевого слова using расширяются области видимости всех членов пространства имен. Впоследствии это позволяет ссылаться на члены пространства имен, не указывая соответствующее имя пространства. Использование using показано в следующем примере:
namespace Window {
int valuo1 = 20;
int value2 - 40;
}
...
Window::value1 = 10;
using namespace Window;
value2 = 30;
Все члены пространства имен Window становятся видимыми, начиная от строки using namespace Window; и до конца соответствующего модуля программы. Обратите внимание, что если для обращения к переменной value1 в верхней части фрагмента программы необходимо указывать пространство имен, то в этом нет необходимости при обращении к переменной value2, поскольку оператор using сделал видимыми все члены пространства имен Window.
Оператор using может использовать в любом модуле программы с различной областью видимости. Когда выполнение программы выходит за область видимости данного модуля, автоматически становятся невидимыми все члены пространства имен, открытые в этом модуле. Проанализируйте это на следующем примере:
namespace Window {
int value1 = 20;
int value2 = 40 ;
}
//...
void f
{
{
using namespace Window ; value2 = 30 ;
}
value2 = 20 ; //ошибка!
}
Последняя строка кода функции f — value2 = 20 — вызовет ошибку во время компиляции, поскольку переменная value2 в этом месте невидима. Видимость этой переменной, заданная оператором using, закончилась сразу за закрывающими фигурными скобками в предыдущей строке программы.
В случае объявления внутри модуля локальных переменных все одноименные переменные пространства имен, открытые в этом модуле, будут скрыты. Это аналогично сокрытию глобальных переменных локальными в случае совпадения их областей видимости. Даже если переменная, объявленная в пространстве имен, будет открыта с помощью using после объявления локальной переменной, последняя все равно будет иметь приоритет. Это наглядно показано в следующем примере:
namespace Window {
int value1 = 20;
int value2 = 40 ;
}
//...
void f
{
int value2 = 10;
using namespace Window;
std::cout << value2 << std::endl;
}
При выполнения этой функции на экране появится значение 10, а не 40, подтверждая тот факт, что переменная value2 пространства имен Window скрывается переменной value2 функции f. Если все же требуется использовать переменную пространства имен, явно укажите имя пространства.
При использовании одноименных идентификаторов, один из которых объявлен как глобальный, а другой — внутри пространства имен, также может возникнуть двусмысленность. Чтобы избежать ее, всегда явно указывайте имя пространства при вызове объекта, как в следующем фрагменте программы:
namespace Window {
int value1 = 20;
}
//...
using namespace Window;
int value1 = 10;
void f
{
value1 = 10 ;
}
В данном примере неопределенность возникает внутри функции f. Оператор using сообщает переменной Window::value1 глобальную область видимости. Однако в программе объявляется другая глобальная переменная с таким же именем. Какая из них используется в функции f? Обратите внимание, что ошибка будет показана не во время объявления одноименной глобальной переменной, а при обращении к ней в теле функции f.