рефераты

рефераты

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

Меню

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

struct S (* ... *);

int S(struct S *Sptr);

void func(void)

(*

S t; // недопустимое объявление: нет ключа класса // и функции S в контексте struct S s; // так можно: есть уточнение ключем класса

S(&s); // так можно: это вызов функции

*)

С++ позволяет также неполное объявление класса:

class X;// еще нет компонентов !

struct Y;

union Z;

Неполные объявления позволяют некоторые ссылки к именам классов X, Y или Z (обычно ссылки на указатели объектов классов) до того, как классы будут полностью определены (см. "Объявление компонентов структуры" на стр.65 оригинала). Разумеется, прежде чем вы сможете объявить и использовать объекты классов, вы должны выполнить полное объявление классов со всеми их компонентами.

Объекты классов

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

Список компонентов класса

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

Функции-компоненты

Функция, объявленная без спецификатораfriend, называется функцией-компонентом класса. Функции, объявленные с модификатором friend, называется "функцией-другом".

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

Ключевое слово this

Не-статические функции компонентов работают с объектами типа класса, с которыми они вызываются. Например, если xэто объект класса X, а f это функция-компонент X, то вызов функци x.f() работает с x. Аналогичным образом, если xptr есть указатель объекта X, то вызов функции xptr->() работает с *xptr. Откуда f может знать, с каким x работать? С++ передает f указатель на x, называемый this. this передается как скрытый аргумент при вызове не-статических функций-компонентов.

Ключевоеслово this представляет собой локальную переменную, доступную в теле не-статической функции-компонента. this не требует объявлений, и на него редко встречаются явные ссылки в определении функции. Однако, оно неявно используется в функции для ссылки ккомпонентам. Если, например, вызывается x.f(y), где y есть компонент X, то this устанавливается на &x, а y устанавливается на this->y, что эквивалентно x.y.

Встраиваемые функции (inline)

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

В некоторых случаях Turbo C++ может уменьшить затраты времени на вызов функции, подстанавливая вместо вызова функции непосредственно компилированный код тела функции. Этот процесс, называемый встраиваемым расширением тела функции, не влияет на контекст имени функции или ее аргументов. Встраиваемое расширение не всегда полезно и желательно. Спецификатор inline представляет собой запрос (или требование) компилятору, в котором вы сообщаете, что встраиваемые расширения желательны. Как и в случае спецификатора класса памяти register, компилятор может либо удовлетворить, либо проигнорировать ваше пожелание.

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

int i;                 // global int

class X (*

public:

char* func(void) (* return i; *) // inline по умолчанию char* i;

*);

эквивалентно

inline char* X::func(void) (*return i; *)

func определяется "вне" класса с явным спецификатором inline. Переменная i, возвращаемая func, есть char* i класса X - см. раздел, посвященный контексту компонентов на стр.107 оригинала.

Статические компоненты

Спецификатор класса памяти static может быть использован в объявлениях компонентов данных и функций-компонентов класса. Такие компоненты называются статическими и имеют свойства, отличные от свойств не-статических компонентов.В случае не-статических компонентов для каждого объекта класса "существует" отдельная копия; в случае же статических компонентов существует только одна копия, а доступ к ней выполняется без ссылки на какой-либо конкретный объект класса. Если х это статический компонент класса Х, то к нему можно обратиться как Х::х (даже если объекты класса Х еще не созданы). Однако, можно выполнить доступ к х и при помощи обычных операций доступа к компонентам. Например, в виде y.x и yptr->x, гдеy это объект класса X, а yptr это указатель объекта класса X, хотя выражения y и yptr еще не вычислены. В частности, статическая функция-компонент может быть вызвана как с использованием специального синтаксиса вызова функций компонентов, так и без него.

class X (*

int member_int;

public:

static void func(int i, X* ptr);

*);

void g(void);

(*

X obj;

func(1, &obj);  // ошибка, если где-нибудь еще

// не определена глобальная func()

X::func(1, &obj); // вызов static func() в X // допустим только для статических функций

obj.func(1, &obj); // то же самое (допустимо как для стати// ческих, так и не-статических функций)

*)

Поскольку статическая функция-компонент может вызываться без учета какого-либо конкретногообъекта, она не имеет указателя this. Следствие из этого таково, что статическая функция-компонент не имеет доступа к не-статическим компонентам без явного задания объекта при помощи .или ->. Например, сучетомобъявлений, сделанных впредыдущем примере, func может быть определена следующим образом:

void X%%func(int i, X* ptr)

(*

member_int = i;                       // на какой объект ссылается

// member_int? Ошибка !

ptr->member_int = 1; // так можно: теперь мы знаем! *)

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

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

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

class X (*

...

static int x;

...

*); int X::x = 1;

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

- уменьшения числа видимых глобальных имен

- того, чтобы сделать очевидным, какие именно статические объекты какому классу принадлежат

- разрешения управления доступам к их именам.

Контекст компонента

Выражение X::func() в примере, приведенномна стр.106 оригинала, используетимя класса Xс модификатором контекста доступа, обозначающим, что func, хотя и определена "вне" класса, в действительности является функцией-компонентом Х и существует в контексте Х. Влияние Х:: распространяется на тело определения этой функции. Это объясняет, почему возвращаемое функциейзначение i относится к X::i, char* i из Х, а не к глобальной переменной int i. Без модификатора Х:: функция func представляла бы обычную, не относящуюся к классу функцию, возвращающую глобальную переменную int i.

Следовательно, все функции-компоненты находятся в контексте своего класса, даже если они определены вне этого класса.

К компонентам данных класса Х можно обращаться при помощи операций выбора . и -> (как и в структурах С). Функциикомпоненты можновызывать также при помощи операций выбора (см. "Ключевое слово this на стр.105 оригинала). Например,

class X (*

public:

int i;

char name[20];

X *ptr1;

X *ptr2;

void Xfunc(char *data, X* left, X* right); // определение // находится не здесь

*);

void f(void);

(*

X x1, x2, *xptr=&x1; x1.i = 0; x2.i = x1.i; xptr->i = 1; x1.Xfunc("stan", &x2, xptr);

*)

Если m является компонентом или базовым компонентом класса Х, то выражение Х::m называется квалифицированным именем; оно имеет тот же тип, что и m, и является именующим выражением только в том случае, если именующим выражением является m. Ключевой момент здесьсостоит в том, что даже если имя класса Х скрыто другим именем, квалифицированное имя Х::m тем не менее обеспечит доступ к нужному имени класса, m.

Компоненты класса не могут быть добавлены к нему в другом разделе вашейпрограммы. Класс Х не может содержать объекты класса Х, но может содержать указатели или ссылки на объекты класса Х (отметим аналогию с типами структур и объединений С).

Управление доступом к компонентам

Компоненты класса получают атрибуты доступа либо по умолчанию (взависимости от ключакласса и местоположения объявления), либо при использовании какого-либо из спецификаторов доступа: public, private или protected. Значение этих атрибутов следующие:

public Компонент может быть использован любой функцией.

private Компонент может быть использован только функциями компонентами и "друзьями" класса, в котором он объявлен.

protected То же самое, что для private, но кроме того, компонент может быть использован функциями компонентов идрузьями классов, производных от объявленного класса,но только в объектах производного типа. (Производные классы рассматриваются в следующем разделе).

Спецификаторы доступа не влияют на объявления функций типа friend. (См. раздел "Друзья" классов" на стр.112 оригинала).

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

Компоненты struct по умолчанию имеют атрибут public, но вы можете переопределитьэто умолчаниепри помощи спецификаторов доступа public или protected.

Компоненты union поумолчанию имеют атрибут public; переопределить его нельзя. Все три спецификатора доступа задавать для компонентов объединения недопустимо.

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

class X (*

int i;   // X::i по умолчанию privte

char ch;                // так же, как и X::ch

public:

int j;   // следующие два компонента - public

int k;

protected:

int l;   // X::l - protected

*);

struct Y (*

int i;   // Y::i по умолчанию public

private:

int j;   // Y::j - private

public:

int k;   // Y::k - public

*);

union Z (*

int i;   // public по умолчанию, других вариантов нет

double d;

*);

Спецификаторы доступа могут быть перечислены и сгруппированы в любой удобной последовательности.Можно сэкономить место при набивке программы, объявив все компоненты private сразу, и т.д.

Доступ к базовым и производным классам

При объявлении производного класса D вы перечисляете базовые классы В1, В2 ... в разделяемом запятой базовом-списке:

ключ-класса D:базовый-список (*<список-компонентов>*)

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

D наследует всем компонентамбазовых классов. (Переопределенные компоненты базовых классов наследуются, ипри необходимостидоступк нимвозможен при помощи переопределений контекста). D может использовать только компоненты базовых классов с атрибутами public и protected. Однако, что будут представлять собойатрибуты доступа унаследованных компонентов с точки зрения D? D может понадобиться использоватьpublicкомпонент базового класса, но при этом сделать его для внешних функций private. Решение здесь состоитв том, чтобыиспользовать спецификаторы доступа в базовом-списке.

При объявлении D вы можете задать спецификатор доступа public или private перед классами в базовом-списке:

class D : public B1, private B2, ... (*

...

*)

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

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

Умолчанием является private, если D есть объявление класса class, и public, если D есть объявление структуры struct.

Производный класс наследует атрибуты доступа базового класса следующим образом:

базовый класс public: компоненты public базового классастановятся членами public производного класса. Компоненты pro- tected базового класса становятся компонентами protected производногокласса. Компоненты private базового класса остаютсядля базового класса private.

базовый класс private: и public, и protected компоненты базового классастановятся private компонентами производного класса.Компоненты private базового класса остаются для базового класса private.

В обоих случаях отметим, что компоненты private базового класса былии остаются недоступными дляфункций-компонентов производного класса, пока в описании доступа базового класса не будут явно заданы объявления friend. Например,

class X : A (*                        // умолчание для класса - private A

...

*)

/* класс X является производным от класса А */

class Y : B, public C (* // переопределяет умолчание для С

...

*)

/* класс Y является производным (множественное наследование) от B и C. По умолчанию - private B */

struct S : D (*                       // умолчание для struct - public D

...                     /* struct S - производная от D */

*)

struct T : private D, E (* // переопределяет умолчание для D // E по умолчанию public

...

*)

/* struct T является производной (множественное наследование) от D и T. По умолчанию - public E */

Действие спецификаторов доступа в базовом списке можно скорректировать при помощи квалифицированного-имени вобъявлениях public или protected для производного класса. Например,

class B (*

int a;                     // по умолчанию private

public:

int b, c;

int Bfunc(void);

*);

class X : private B (* // теперь в Х a, b, c и Bfunc - private int d; // по умолчанию private. Примечание: f

// в Х недоступна

public:

B::c;              // c была private; теперь она  public

int e;

int Xfunc(void);

*);

int Efunc(X& x);   // внешняя по отношению к В и Х

Функция Tfunc может использовать только имена с атрибутом public, например c, e и Xfunc.

Функция Xfunc в X является производной от private B, поэтому она имеет доступ к:

- "скорректированной-к-типу-public" c

- "private-относительно-Х" компонентам В:b и Bfunc

- собственным private и public компонентам: d, e и Xfunc.

Однако, Xfunc не имеет доступа к "private-относительно- B" компоненту a.

Виртуальные базовые классы

При множественном наследованиибазовый класс не может быть задан в производном классе более одного раза:

class B (* ... *);

class D : B, B (* ... *):  // недопустимо

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

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

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

class Z : public X, public Y (* ... *)  // допустимо

В данном случае каждый объект класса Z будет иметь два подобъекта класса В. Если это вызывает проблемы, к спецификатору базового класса может бытьдобавлено ключевое слово virtual. Например,

class X : virtual public B (* ... *)

class Y : virtual public B (* ... *)

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

Теперь В является виртуальным базовым классом,а класс Z имеет только один под-объект класса В.

"Друзья" классов (friend)

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

Поскольку F не является компонентом Х, она не лежит в контексте Х и поэтому не может вызываться операциями выбора x.F и xptr->F (где x это объект Х, а xptr это указатель объекта Х.

Страницы: 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