Пространство имен. Пространство имен как объявление. Пространство имен как директива

Пространства имен .

При совпадении имен разных элементов в одной области действия часто

возникает конфликт имен. Наиболее часто это возникает при использовании

различных пакетов библиотек, содержащих, например, одноименные классы.

Пространства имен используются для разделения глобального пространства

имен, что позволяет уменьшить количество конфликтов.

 

Ключевое слово using как директива.

Инструкция using namespace имя позволяет предоставить все имена,

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

#include <iostream>

using namespace std;

namespace NAME

{ int n1=1;

int n2=2;

}

// int n1; приводит к неоднозначности в main для переменной n1

int main()

{ NAME::n1=3;

// n1=3; // error 'n1' : undeclared identifier

// n2=4; // error 'n2' : undeclared identifier

using namespace NAME; // далее n1 и n2 доступны

n2=4;

cout << n1 <<" "<< n2 << endl; // результат 3 4

{ n1=5;

n2=6;

cout << n1 <<" "<< n2 << endl; // результат 5 6

}

return 0;

}

В результате выполнения программы получим:

3 4

5 6

Область действия директивы using распространяется на блок, в котором

она использована, и на все вложенные блоки.

Если одно из имен относится к глобальной области, а другое объявлено

внутри пространства имен, то возникает неоднозначность. Это проявится только

при использовании этого имени, а не при объявлении.

#include <iostream>

using namespace std;

В данном фрагменте стандартный заголовочный файл библиотеки вво-

да/вывода iostream не имеет расширения. Все содержимое этого файла определяется как часть namespace std. Для достижения переносимости рекомендуется использовать директиву using, хотя и существуют компиляторы, не поддерживающие данную возможность. Основная проблема, которую призвана решить такая конструкция это не-

зависимость от ограничения на длину имени файла в различных операционных системах. Более того, компиляторы Microsoft последних версий вообще не поддерживают вариант с подключением файлов стандартной библиотеки с расширением .h, т.е. конструкция #include <iostream.h> в Visual C++ 7.1 не компилируется.

Ключевое слово using как объявление.

Объявление using имя::член подобно директиве, при этом оно обеспечивает более подробный уровень управления. Обычно using используется для объ-

явления некоторого имени (из пространства имен) как принадлежащего текущей области действия (блоку).

#include <iostream>

using namespace std;

namespace NAME

{ int n1=1;

int n2=2;

}

int main()

{ NAME::n1=3;

// n1=4; error 'n1' надо указывать полностью NAME::n1

// n2=5; error 'n2' : undeclared identifier

// int n2; следующая строка приводит к ошибке

using NAME::n2; // далее n2 доступно

n2=6;

cout <<NAME::n1<<" "<< n2 << endl; // результат 3 6

{ NAME::n1=7;

n2=8;

cout <<NAME::n1<<" "<< n2 << endl;// результат 7 8

}

return 0;

}

В результате выполнения программы получим:

3 6

7 8

Объявление using добавляет определенное имя в текущую область дейст-

вия. В примере к переменной n2 можно обращаться без указания принадлежности классу, а для n1 необходимо полное имя. Объявление using обеспечивает более подробное управление именами, переносимыми в пространство имен. Это и есть ее основное отличие от директивы, которая переносит все имена пространства имен. Внесение в локальную область (блок) имени, для которого выполнено явное объявление (и наоборот), является серьезной ошибкой.

 

 

Виртуальные функции

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

а затем вверх по иерархии до деструктора базового класса.

class Shape

{protected:

double s;

public:

Shape(char *fig) : s(0)

{ cout << " конструктор класса Shape (фигура "<< fig <<')'<< endl;}

virtual ~Shape()

{ cout << " деструктор класса Shape " << endl;}

void virtual print()

{cout<<s<<endl;}

void virtual area()=0;

};

class Circle : public Shape

{ int r;

public:

Circle(char *name,int r): Shape(name)

{ cout << " конструктор класса Circle "<<endl;

this->r=r;

}

~Circle()

{ cout << " деструктор класса Circle " << endl;}

void area();

};

void Circle::area()

{ s=r*r*3.14; cout<<" Площадь круга = "; this->print();

}

int main()

{ Shape *fg1;

fg1=new Circle("("Круг ",2); fg1->area(); delete fg1; return 0;

}

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

при удалении объектов производных классов осуществлялся бы вызов только

деструктора класса соответствующего ему типа , т.е. базового класса (класса,

для которого объявлен соответствующий указатель).

Если в классе имеются виртуальные функции, то желательно объявлять

деструктор этого класса также виртуальным, даже если этого не требуется. Это

может предотвратить возможные ошибки.