Программирование >>  Структура ядра и системные вызовы 

1 2 3 4 [ 5 ] 6 7 8 ... 98


операции расширения области видимости Имя, стоящее слева от знака операцииэто имя класса, а имя, стоящее справа от него, - переменная или функция, определенная в классе. Например, тепиг.питобозначает данное-член питJields класса menu. Если слева от знака операции расширения области видимости имени нет, то имя, указанное справа, представляет собой глобальную переменную или функцию. Например, если есть глобальная переменная х, а в объявлении класса есть данное-член х, то функции-члены этого класса могуг обращаться к глобальной переменной х посредством записи ::х, а к данному-члену л: - с использованием записи х или записи <имя класса>: .х.

В следующем заголовке menu.h объявляется класс тени:

#ifndef MENU H #define MENU H

class menu {

private:

char* title; protected:

static int num fields; public:

функция-конструктор menu( const char* str г

#endif

/*menu.h*/

title = new char[strlen(str)+1]; strcpy (title, str) , num fields =0;

./:/ функция-конструктор menu 0

title = 0; num fields

функция-деструктор

~menu(}

delete title;

void incr field( int size=l )

{ .

num fields+=size;

static int fieJfdsO {

return num fields;

char* nameO

return title;

В данном примере члены тепи::пит Jields и menu::fields() объявлены как статические. При таком объявлении объекты получают доступ к одному экземпляру каждого статического данного-члена. В противном случае каждый объект получает собственную копию этих членов. Статические данные-члены используются как глобальные переменные всеми объектами этого же типа. Доступность статических данных-членов для объектов других классов определяется тем, как они объявлены: как закрытые, защищенные или открытые.

Статические данные-члены, если они используются в профамме, должны определяться в исходном модуле. Рассмотрим в качестве примера определение данного-члена тепиг.пит Jields с нулевым начальным значением:

имя модуля: а.С ,

♦ include <string.h>

♦ include menu.h int menu::num fields = 0;

int main 0 { . . . }

Хотя здесь тепиг.питJields - защищенное данное-член, его можно определить и инициализировать в области видимости программы. Однако дальнейшее изменение этой переменной в пользовательских программах должно производиться только через функции-члены класса menu, функции подклассов или дружественные функции. Это же правило касается закрытых статических данных-членов.

Статические функции-члены могут обращаться только к статическим данным-членам в классе. Так, в классе menu функция menu::fields() не может обращаться к данному-члену menu:-.title. В то время как нестатические функции-члены должны вызываться через объекты класса, статические функции такого ограничения не имеют:

menu abc ( Example ); ,

abc.incr field( 5 ); . э-

cout static func. called independent of objects:

<<menu::fields 0<<endl; of-

cout Static func. can also be called via object:

abc. fields 0 endl; **

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

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



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

menu abc; используется menu::menu()

menu xyz( Example ); используется menu::menu( const char* str)

Функция menu()::~menuO является деструктором. Она вызывается тогда, когда объект класса выходит из области видимости, и предназначена для обеспечения завершения обработки данных надлежащим образом (например, освобождения используемой объектом динамической памяти). Функция-деструктор не перегружается и не принимает аргументов.

В примере с классом menu все определения функций-членов размещены в объявлении класса. Это значит, что эти функции-члены будут использоваться как встроенные (inline) функции (в языке С аналогом встроенных функций являются макроопределения). Преимущество использования inline-функций состоит в повышении производительности программ благодаря отсутствию дополнительных затрат на вызовы функций. У встроенных функций есть и недостаток: любые изменения в такой функции требуют перекомпиляции исходных модулей, содержащих ссылки на нее.

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

tifndef MENU H ♦define MENU Н

class menu

private: . r char* title; .! protected:

static int nura fields; public:

конструктор

menu( const char* str );

menu 0 ; деструктор -menu() ;

void incr field( int si2e=l static int fields 0; char* nameO ;

#endif

/*menu.h*/

Тогда для определения функций-членов нужно создать отдельный модуль С++, например, menu.С:

JI source file name: menu,С ♦include <string.h> ♦include menu.h int menu::num fields = 0;

конструктор с аргументом > . menu::menu ( const char* str ) {

title = new char[strlen(str)+1]; strcpy (title, str ); num fields = 0;

конструктор без аргумента

menu::menu О

title = 0; num fields =0;

деструктор menu::~menu() {

delete title;

нестатическая функция-член void menu: :ir\cr field ( int siz ) 1

num fields += siz;

статическая функция-член int menu::fields 0

return num fields;

еще одна нестатическая функция-член char* menu::name()

.return title;

Любая программа, которая использует класс menu для создания исполняемого объекта, должна компилироваться совместно с файлом тепи.С. Возьмем, например, файл testmenu. С:

II source test menu.C ♦include <iostream.h> ♦include menu.h int main() (

menu abc ( Test ); cout abc.name(); return menu::fields 0;

Путем компилирования файла testmenu.C создается выполняемая программа a.out.

% cc test menu.C menu.С

% a.out

Test



в дополнение к сказанному отметим, что в объявлении функции тепигАпсг Jleld в файле menu.h аргумент size имеет значение по умолчанию, тогда как в файле menu. С в определении функции menu::incr Jield указывать значение по умолчанию для этого аргумента не разрешается. В С++ 1.0 подобное объявление было возможно, но поскольку его использование может привести к противоречиям в присвоении значений по умолчанию аргументам функций, в последующих версиях оно не допускается.

2.3. Дружественные функции и классы

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

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

В приведенном ниже примере демонстрируется использование дружественной функции и дружественного класса:

source module: friend.С

♦include <iostream.h>

int year;

class foo;

class dates

friend ostreams operator (ostream&,dates&) ; int year, month, day; public:

friend class foo;

dates(} { year=month=day = 0; };

-dates(} {);

int sameDay(int d} const { return d==day; ); void set(int y) const { ::year = y; }; void set(int y} { year iiy; }

class foo {

public:

void set(dates& D, int year) {D.year = year; };

ostreams operator (ostreams os, datess D) (

OS D.year , D.month , D.day; return os;

int mainO {

dates Dobj;

foo Fobj;

Fobj.set(Dobj, 1998);

clog Dobj: Dobj Xn;

return 0;

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

% СС friend.с % а.out

Dobj: 1998, О, О

2.4. Функции-члены, объявленные с декларацией const

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

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

В следующем примере показано, как определяются и используются функции-члены с декларацией const

source module: const.С ♦include <iostream.h> static int year = 0; ulass dates

{

int year, month, day;

public:

dates 0 { year=month=day = 0; };



1 2 3 4 [ 5 ] 6 7 8 ... 98

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика