рефераты

рефераты

 
 
рефераты рефераты

Меню

Реферат: Turbo C++ Programer`s guide рефераты

Если в объявлении или определении функции в пределах класса Х используется спецификатор friend, то такаяфункция становится "другом" класса Х.

Функция-"друг", определенная в пределах класса, подчиняется тем же правилам встраивания, что и функции-компоненты класса (см. "Встраиваемые функции" на стр.105 оригинала). Функции-"друзья" не зависят от их позиции в классе или спецификаторов доступа. Например,

class X (*

int i; // private относительно Х

friend void friend_func(X*, int);

/* friend_func не является private, хотя она и объявлена

в разделе private */

public:

void member_func(int);

*);

/*объявления;для обеих функций отметим доступ к private int i*/

void friend_func(X* xptr, int a) (* xptr->i = a; *)

void X::member_func(int a) (* i = a; *)

X xobj;

/* отметим различие в вызовах функций */

friend_func(&xobj, 6);

xobj.member_func(6);

Вы можете сделать все функции класса Y друзьями класса Х в одном объявлении:

class Y;                        // неполное объявление

class X (*

friend Y;

int i;

void member_funcX();

*);

class Y; (*

void friend_X1(X&);

void friend_X2(X*);

...

*);

Функции, объявленные в Y, являются друзьями Х, хотя они и не имеютспецификаторовfriend. Они имеют доступ к компонентам Х private, таким как i и member_funcX.

Отдельные функции-компоненты класса Хтакже могут быть друзьями класса Y:

class X (*

...

void member_funcX();

*)

class Y (*

int i;

friend void X::member_funcX();

...

*);

"Дружба" классов не транзитивна: если X друг Y, а Y друг Z, это не означает, что X - друг Z. Однако, "дружба" наследуется. Конструкторы и деструкторы

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

1. Они не имеют объявлений значений возврата (даже void).

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

3. Конструкторы, как и большинство функций С++, могут иметь аргументы по умолчанию или использовать списки инициализации компонентов.

4. Деструкторы могут иметь атрибут virtual, но конструкторы не могут.

5. Вы не можете работать с их адресами:

main()

(*

...

void *ptr = base::base;  // недопустимо

...

*)

6. Если конструкторы и деструкторы не были заданы явно, то они могут быть сгенерированы Turbo C++; во многих случаях они также могут быть запущены при отсутствии явного вызова в вашей программе. Любой конструктор или деструктор, создаваемый компилятором, должен иметь атрибут public.

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

8.

(*

...

X *p;

...

p->X::-X();// допустимый вызов деструктора

X::X();// недопустимый вызов конструктора

...

*)

9. При определении и разрушении объектов компилятор выполняет вызов конструкторов и деструкторов автоматически.

10.Конструкторы и деструкторы при необходимости распределения объекту памяти могут выполнять неявные вызовы операций new и delete.

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

Если класс Х имеет один или более конструкторов, то один из них запускается всякий разпри определении объекта х класса Х. Конструктор создает объект х и инициализирует его. Деструкторы выполняют обратный процесс,разрушая объекты класса, созданные конструкторами.

Конструкторы активизируются также при создании локальныхили временных объектов данного класса;деструкторы активизируются всякий раз, когда эти объекты выходят из контекста. Конструкторы

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

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

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

class x

(*

public:

X();             //конструктор класса Х

*);

Конструктор класса Х не может принимать Х как аргумент:

class X (*

...

public

X(X); // недопустимо *)

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

Конструктор по умолчанию

Конструктором по умолчанию для класса Х называется такой конструктор, который не принимает никаких аргументов: Х::Х(). Если длякласса несуществует конструкторов, определяемых пользователем, то Turbo C++ генерирует конструктор по умолчанию. При таких объявлениях, как Х х, конструктор по умолчанию создает объект х.

Важное примечание:

Как и все функции, конструкторымогут иметь аргументы по умолчанию. Например, конструктор

X::X(int, int = 0)

можетпринимать один или два аргумента. Если данный конструктор будет представлен только с одним аргументом,недостающий второй аргумент будет принят как int 0. Аналогичным образом, конструктор

X::X(int = 5, int = 6)

может принимать двааргумента, один аргумент, либо не принимать аргументов вообще,причем в каждом случаепринимаются соответствующие умолчания. Однако, конструктор по умолчанию Х::Х() не принимаетаргументов вообще, иего не следует путать с конструктором, например, X::X(int = 0), который может либо принимать один аргумент, либо не принимать аргументов.

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

class X

(*

public:

X();

X(int i = 0);

*);

main()

(*

X one(10);  // так можно: используется X::X(int)

X two; // так нельзя; неоднозначно задано, используется // ли X::X() или X::X(int = 0)

...

return 0;

Конструктор копирования

Конструктор копированиядля класса Х это такой конструктор, который может быть вызван с одним единственным аргументом типа X: X::X(const X&) или X::(const X&, int = 0). В конструкторе копирования допустимыми такжеявляются аргументы по умолчанию. Конструкторыкопирования запускаются при копировании объекта данного класса, обычно в случае объявления с инициализацией объектом другого класса: X x = y. Turbo C++ генерирует конструктор копирования для класса X автоматически, если такой конструктор необходим, но в классе Х неопределен.

Перегрузка конструкторов

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

class X

(*

int   integer_part;

double double_part;

public:

X(int i)                 (* integer_part = i; *)

X(double d) (* double_part = d *)

*);

main()

(*

X one(10); // запускает X::X(int) и устанавливает // integer_part в значение 10

X one(3.14); // запускает X::X(double) ш устанавливает // double_part

...

return 0;

*)

Порядок вызова конструкторов

В случае, когда класс использует одинили более базовых классов, конструкторы базовых классов запускаются до того, как будутвызваны конструкторы производного класса. Конструкторы базового класса вызываются в последовательности их объявления.

Например, в следующем примере

class Y (*...*)

class X : public Y (*...*)

X one;

вызов конструкторов происходит в следующей последовательности:

Y();             // конструктор базового класса

X();             // конструктор производного класса

В случае множественных базовых классов:

class X : public Y, public Z

X one;

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

Y(); // первыми следуют конструкторы базового класса Z();

X();

Конструкторы виртуальных базовых классов запускаются до каких-либо не-виртуальных базовых классов. Если иерархия содержит множественные виртуальные базовые классы, то конструкторы виртуальных базовых классов запускаются в последовательности их объявления. Затем,перед вызовомконструкторов производного класса, конструируются не-виртуальные базовые классы.

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

class X : public Y, virtual public Z

X one;

определяет следующую последовательность:

Z(); // инициализация виртуального базового класса Y(); // не-виртуальный базовый класс

X();   // произвольный класс

Либо, в более сложном случае,

class base;

class base2;

class level1 : public base2, virtual public base; class level2 : public base2, virtual public base; class toplevel : public level1, virtual public level1; toplevel view;

Порядок конструирования view будет принят следующий:

base(); // старший в иерархии виртуальный базовый класс // конструируется только однажды

base2(); // не-виртуальная база виртуальной базы level2 // вызывается для конструирования level2

level2(); // виртуальный базовый класс

base2(); // не-виртуальная база для level1

level1(); // другая не-виртуальная база

toplevel();

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

Конструкторы элементовмассива запускаютсяв порядке возрастания индексов массива.

Инициализация класса

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

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

class X

(*

int i;

public:

X();             // тела функций для ясности опущены

X(int x);

X(const X&);

*);

main()

(*

X one;                // запуск конструктора по умолчанию

X two(1);                  // используется конструктор X::X(int)

X three = 1;  // вызывает X::X(int)

X four = one; // запускает X::X(const X&) для копирования X five(two);  // вызывает X::X(cont X&)

Конструктор может присваивать значения своимкомпонентам следующим образом. Он может принимать значения в качестве параметров и выполнять присваивание компонентам переменным собственно в теле функции конструктора:

class X

(*

int a, b;

public:

X(int i, int j) (* a = i; b = j *)

*);

Либо он может использовать находящийся до тела функции список инициализаторов:

class X

(*

int a, b;

public:

X(int i, int j) : a(i), b(j) (**)

*);

В обоих случаях инициализация X x(1, 2) присваивает значение 1 x::a и значение 2 x::b. Второй способ, а именно список инициализаторов, обеспечивает механизм передачи значений конструкторам базового класса.

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

class base1

(*

int x;

public:

base1(int i) (* x = i; *)

*);

class base2

(*

int x;

public:

base2(int i) : x(i) (**)

*);

class top : public base1, public base2

(*

int a, b;

public:

top(int i, int j) : base(i*5), base2(j+i), a(i) (* b = j;*)

*);

В случае такойиерархии класса объявление top one(1, 2) приведет к инициализации base1 значением 5, а base2 значением 3. Методы инициализации могут комбинироваться друг с другом.

Как было описано выше, базовые классы инициализируются в последовательности объявления.Затем происходит инициализация компонентов, также в последовательности их объявления, независимо от их взаимного расположения в списке инициализации.

class X

(*

int a, b;

public:

X(int i, j) : a(i), b(a+j) (**)

*);

В пределах класса объявление X x(1,1) приведет к присваиванию числа 1 x::a и числа 2 x::b.

Конструкторы базовых классов вызываются перед конструированием любых компонентов производных классов. Значения производного класса не могут изменяться и затем влиять на создание базового класса.

class base

(*

int x;

public:

base(int i) : x(i) (**)

*);

class derived : base

(*

int a;

public:

derived(int i) : a(i*10), base(a) (**) // Обратите внимание! // base будет передано неинициализированное a

*)

В данномпримере вызовпроизводного d(1) неприведет к присвоению компоненту базового класса х значения 10. Значение, переданное конструктору базового класса, будет неопределенным.

Если вы хотите иметь список инициализаторов в не-встроенном конструкторе,не помещайте этот список вопределении класса. Вместо этого поместите его в точку определения функции:

derived::derived(int i) : a(i)

(*

...

*)

Деструкторы

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

class X

(*

public:

-X();  // деструктор класса X

*);

Если деструкторне объявлен для класса явно, компилятор генерирует его автоматически.

Запуск деструкторов

Вызов деструктора выполняется неявно, когда переменная выходит из своего объявленного контекста. Для локальных переменных деструкторы вызываются, когда перестает быть активным блок, в котором они объявлены. В случае глобальных переменныхдеструкторы вызываются как часть процедуры выхода после main.

Когда указатели объектов выходят запределы контекста, неявный вызов деструктора непроисходит. Это значит, чтодля разрушения такого объекта операция delete должна быть задана явно.

Деструкторы вызываются строго в обратной последовательности относительнопоследовательности вызова соответствующих им конструкторов (см. стр.117 оригинала).

atexit, #pragma exit и деструкторы

Все глобальные объекты остаются активными до тех пор, пока не будут выполнены коды во всех процедурах выхода. Локальные переменные, включая те, что объявлены в main, разрушаютсяпри выходе их из контекста. Последовательность выполнения в конце программы Turbo C++ в этом смысле следующая:

- выполняются функции atexit в последовательности их вставки в программу

- выполняются функции #pragma exit в соответствии с кодами их приоритетов

- вызываются деструкторы глобальных переменных.

exit и деструкторы

При вызове exitиз программы деструкторы для каких-либо локальных переменных в текущем контексте не вызываются. Глобальные переменные разрушаются в обычной последовательности.

abort и деструкторы

При вызове abort где-либо из программы деструкторы не вызываются, даже для переменных глобального контекста.

Деструктор можетбыть также вызван явно, одним из двух следующих способов: косвенно, через вызовdelete, или прямо, задавая полностью квалифицированногоимени деструктора. Delete можноиспользовать для разрушения объектов, для которых память распределялась при помощи new. Явный вызов деструктора необходим только в случае объектов, которым распределялся конкретный адрес памяти при помощи new.

class X (*

...

-X();

...

*);

void* operator new(size_t size, void *ptr)

(*

return ptr;

*)

char buffer[sizeof(x)];

main()

(*

X* pointer = new X;

X* exact_pointer;

exect_pointer =                       new(&buffer)                   X;//                указатель

инициализиру// ется адресом буфера

...

delete pointer;// delete служит для раз-

// рушения указателя

exact_pointer->X::-X();// прямой вызов для отмены

// распределения памяти

*)

Виртуальные деструкторы

Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40