Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Int rn; //индекс числа записей

Поиск

//БД из трех Trecord

определяется объект с именем db шаблонного класса типа TDatabase и задается TRecord в качестве класса, за­мещающего Т в шаблоне. Выражение в скобках (3) — инициализатор db, передаваемый конструктору класса TDatabase.

TDatabase<TRecord> db(3);

//БД из трх указателей

объявля­ется объект dbp класса TDatabase, состоящий из трех указателей на TRecord

TDatabase<TRecord*> dbp(3);

//указатель на БД

TDatabase<TRecord> *pdb;

//указатель на БД указаелей

TDatabase<TRecord*> *ppdb;

cout<< "\n\nDatabase of 3 TRecords\n";

//вызывается функция GetRecord(O)

//для доступа к записи с индексом 0

// Затем в строке вызывается ф-ция-

//член Assign() этого объекта для

//задания строкового значения

db.GetRecord(0).Assign("GeorgeWashington");

db.GetRecord(1).Assign("John Adams");

db.GetRecord(2).Assign("Thomas Jefferson");

for(rn=0; rn<=2;rn++) {cout << db.GetRecord(rn).GetName() << '\n';}

cout << "\n\nDatabase of 3 TRecord pointers\n";

dbp.GetRecord(0) = new TRecord("George Bush");

dbp.GetRecord(1) = new TRecord("Ronald Reagan");

dbp.GetRecord(2) = new TRecord("Jimmy Carter");

for (rn = 0; rn <= 2; rn++)

cout << dbp.GetRecord(rn)->GetName() << '\n';

cout << "\n\nPointer to database of 3 TRecords\n";

pdb = new TDatabase<TRecord>(3);

pdb->GetRecord(0).Assign("John Adams");

pdb->GetRecord(1).Assign("Thomas Jefferson");

pdb->GetRecord(2).Assign("Aaron Burr");

for (rn = 0; rn <= 2; rn++)

cout << pdb->GetRecord(rn).GetName() << '\n';

cout << "\n\nPointer to database of 3 TRecord pointers\n";

ppdb = new TDatabase<TRecord *>(3);

ppdb->GetRecord(0) = new TRecord("Dan Quayle");

ppdb->GetRecord(1) = new TRecord("George Bush");

ppdb->GetRecord(2) = new TRecord("Walter Mondale");

for (rn = 0; rn <= 2; rn++)

cout << ppdb->GetRecord(rn)->GetName() << '\n';

getch();

return 0;

}

После включения заголовочного файла DB.H (строка 3), содержащего объявление шаблонного класса TDatabase, в программе объявляется класс TRecord — один из объектов для запоминания в TDatabase. Класс TRecord очень прост, в нем объявлен в качестве данных-членов только символьный массив name. Однако TRecord на самом деле может быть произвольным классом, так как в классе TDatabase не делается никаких предположений о типе сохраняемых объектов.

В строках 22—25 демонстрируются четыре способа создания объектов класса с помощью шаблона класса. В строке

TDatabase<TRecord> db(3);

определяется объект с именем db шаблонного класса типа TDatabase и задается TRecord в качестве класса, за­мещающего Т в шаблоне. Выражение в скобках (3) — инициализатор db, передаваемый конструктору класса TDatabase.

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

Например, вы можете определить базу данных из 100 вещественных значений двойной точности следующим образом:

TDatabase<double> dbd(100);

Поскольку класс TDatabase написан для сохранения объектов произвольных типов, он называется контей­нерным классом.

Обычно, наилучшие контейнерные классы являются полностью обобщенными, хотя этот идеал часто трудно достичь.

В строках 23-25 демонстрируется создание других экземпляров шаблонного класса. В строке 23 объявля­ется объект dbp класса TDatabase, состоящий из трех указателей на TRecord, в строке 24 — указатель pdb на объект класса TDatabase с незаданным числом объектов типа TRecord. Эти примеры могут покрыть большую часть объектов, которые вы можете захотеть создать на основе других шаблонов класса.

В программе объект класса TDatabase используется так же, как и любой другой не шаблонный объект. На­пример, в строке 28

db.GetRecord(0).Assign("George Washington");

вызывается функция GetRecord(O) для доступа к записи с индексом 0. Затем в строке вызывается функция-член Assign() этого объекта для задания строкового значения.

В строках 34-55 демонстрируется использование других объектов класса TDatabase. Особенно любопытна строка 35:

dbp.GetRecord(O) = new TRecorcK"George Bush");

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

Обратите внимание, что во всех этих примерах вам не надо информировать компилятор с помощью приве­дения типов о типах данных, используемых классом TDatabase. Несмотря на обобщенную природу шаблонов, можно избежать приведения типов и, тем не менее, создавать классы, которые могут поддерживать множество различных типов данных.

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

Разное

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

Указатели на функции-члены

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

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

double (TFirstClass::*myfnptr)(void);

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

void (TFirstClass::*myfnptr)(int, int);

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

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

Листинг 15.14. MFNPTR.CPP (указатели на функции-члены)

«include <iostream.h> «include <iomanip.h>

class TFirstClass { private:

int count; public:

TFirstClassO { count = 0; }

int Access(void);

int (TFirstClass::*myfnptr)(void);

main()

int i; TFirstClass fc;

cout «"\nCall Access the normal way:\n";

for (i = 0; i < 9; i++)

cout «setw(8) «dec «f с AccessO;

cout «"\n\nCall Access via the member function pointer\n";

myfnptr = &TFirstClass::Access;

for (i = 0; i < 9; i++)

cout «setw(8) «dec «(fc.*myfnptr)();

cout «"\n\nMember function pointer and a dynamic instance\n"

TFirstClass *fp = new TFirstClass;

for (i = 0; i < 9; i++)

cout «setw(8) «dec «(fp->*myfnptr)();

return 0;}

int TFirstClass::Access(void) {

return count++; }

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

В функции main() в строке 17 объявляется объект fc класса TFirstClass, в строке 21 вызывается функция-член AccessO класса TFirstClass для объекта fc обычным способом. (Функция AccessO только инкрементиру-ет и возвращает закрытый член класса — должно же в программе хоть что-нибудь выполняться!)

В строке 25 демонстрируется вызов функции-члена AccessO с помощью указателя myfnptr. Для инициали­зации указателя в строке 23 указателю myfnptr присваивается адрес функции-члена AccessO класса TFirstClass. Вы можете также заменить объявление указателя (строка 12) и присваивание (строка 23) одним оператором, глобальным или локальным в функции main():

int (TFirstClass::*myfnptr)(void) = &TFirstClass::Access;

При вызове по указателю функции-члена вы должны придерживаться следующих двух правил.

• Обращайтесь к объекту класса.

• Заключайте в круглые скобки вызов функции.

Например, если п — целочисленная переменная, и fс — объект класса TFirstClass, следующая строка при­своит п результат функции AccessO:

n = (fc.*myfnptr)();

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

n = fc. AccessO;

Можно также вызывать функции-члены с помощью указателей, когда объекты адресуются другими пере­менными-указателями. Например, вернемся к строкам 27-29 в модуле MFNPTR (листинг 15.14). Сначала указателю fp присваивается адрес нового объекта класса TFirstClass. Затем в выражении

(fp->*myfnptr)();

в операторе вывода в поток в строке 29 вызывается функция-член AccessO для объекта, адресованного указа­телем fp. Трехсимвольное выражение ->* — другой вид оператора ссылки на член. Опять же, необходимы до­полнительные скобки, поскольку операция О имеет более высокий приоритет, чем ->*. Предыдущий оператор в точности соответствует следующему:

fp->Access();

В дополнение к адресации функций-членов указателями, можно также ссылаться на другие открытые чле­ны класса. Например, если бы класс TFirstClass имел открытый член типа double с именем balance, вы могли бы объявить указатель на этот член следующим образом:

double TFirstClass:: *dataPtr;

Указатель dataPtr объявляется для адресации любых открытых данных-членов в классе TFirstClass, имею­щих тип вещественных значений двойной точности. Для инициализации указателя следует использовать опе­ратор, подобный следующему:

dataPtr = &TFirstClass::balance;

 

Или же можно объявить указатель и присвоить ему адрес члена balance следующим образом:

double TFirstClass:: «dataPtr = &TFirstClass:.'balance;

В любом случае, указатель dataPtr теперь ссылается на член balance класса TFirstClass. В действительно-1 сти dataPtr не содержит адрес размещения в памяти, вместо этого в нем хранится смещение, по которому член I balance размещается в объекте класса TFirstClass. Остается обратиться к адресованному члену через объект I класса. Следующие операторы, например, инициализируют и отображают значение balance:

fc.balance = 1234.56

cout «"\nBalance=" «fc.*dataPtr;

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

Статические члены

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

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

class TAnyClass {

public:

static void Globallnit(void);

};

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

void TAnyClass::GlobalInit(void) {

// Операторы, которые

//необходимо выполнить}

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

TAnyClass::GlobalInit();

// Вызвать статическую

Функцию Globallnit()

 

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

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

class TAnyClass { private:

static char с;

// Статический член, хранящий данные public:

char GetC(void) { return с; } };

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

char TAnyClass::с = 'q';

В действительности с — глобальная переменная, доступная только функциям-членам TAnyClass. Далее можно определить объект класса TAnyClass, использующий с. Например, следующие операторы определяют объект х и вызывают функцию-член GetC, отображающую символ 'q':

TAnyClass x;



Поделиться:


Последнее изменение этой страницы: 2016-08-01; просмотров: 192; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.117.78.215 (0.008 с.)