Официальный сайт isprras 24/7/365

Вы не зарегистрированы

Авторизация



C++ для начинающих

Фото пользователя Игорь Юрьевич Дяжур
Submitted by Игорь Юрьевич Дяжур on чт, 22/12/2011 - 22:22
Данные об авторе
Автор(ы): 
Дяжур Игорь
Место работы, должность: 

Студент ИТО

МГПИ

Регион: 
Город Москва
Характеристики ресурса
Уровни образования: 
начальное профессиональное образование
Предмет(ы): 
Информатика и ИКТ
Целевая аудитория: 
Учащийся (студент)
Тип ресурса: 
дидактический материал
Краткое описание ресурса: 
<h1 class="title"> Учебник по C++ для начинающих.<strong> </strong>Часть 5. Наследование и шаблоны.</h1>

Часть 5. Наследование и шаблоны

Урок 26. Наследование

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

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

6.      Для инициализации элементов производного класса ваша программа должна вызвать конструкторы базового и производного классов.

7.      Используя оператор точку, программы могут легко обращаться к элементам базового и производного классов.

8.      В дополнение к общим (public) (доступным всем) и частным (private) (доступным методам класса) элементам C++ предоставляет защищенные (protected) элементы, которые доступны базовому и производному классам.

9.      Для разрешения конфликта имен между элементами базового и производного классов ваша программа может использовать оператор глобального разрешения, указывая перед ним имя базового или производного класса.

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

ПРОСТОЕ НАСЛЕДОВАНИЕ

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

class employee

{
public:
   employee(char *, char *, float);
   void show_employee(void);
private:
   char name[64];
   char position[64];
   float salary;
};

Далее предположим, что вашей программе требуется класс manager, который добавляет следующие элементы данных в класс employee:

float annual_bonus;
char company_car[64];
int stock_options;

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

Для определения этого класса вы должны указать ключевое слово class, имя manager, следующее за ним двоеточие и имя employee, как показано ниже:

Производныйкласс//-----> class manager : public employee { <-------// Базовыйкласс

// Здесь определяются элементы
};

Ключевое слово public, которое предваряет имя класса employee, указывает, что общие (public) элементы класса employee также являются общими и в классе manager. Например, следующиеоператорыпорождаютклассmanager.

class manager : public employee

{
public:
   manager(char *, char *, char *, float, float, int);
   void show_manager(void);
private:
   float annual_bonus;
   char company_car[64];
   int stock_options;
};

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

Следующая программа MGR_EMP.CPP иллюстрирует использование наследования в C++ , создавая класс manager из базового класса employee:

#include <iostream.h>

#include <string.h>

class employee

{
public:
   employee(char *, char *, float);
   void show_employee(void);
private:
   char name [ 64 ];
   char position[64];
   float salary;
};

employee::employee(char *name, char *position,float salary)

{
   strcpy(employee::name, name);
   strcpy(employee::position, position);
   employee::salary = salary;
}

void employee::show_employee(void)

{
   cout << "Имя: " << name << endl;
   cout << "Должность: " << position << endl;
   cout << "Оклад: $" << salary << endl;
}

class manager : public employee

{
public:
   manager(char *, char *, char *, float, float, int);
   void show_manager(void);
private:
   float annual_bonus;
   char company_car[64];
   int stock_options;
};

manager::manager(char *name, char *position, char *company_car, float salary, float bonus, int stock_options) : employee(name, position, salary)

{
   strcpy(manager::company_car, company_car) ;
   manager::annual_bonus = bonus ;
   manager::stock_options = stock_options;
}

void manager::show_manager(void)

{
   show_employee();
   cout << "Машинафирмы: " << company_car << endl;
   cout << "Ежегоднаяпремия: $" << annual_bonus << endl;
   cout << "Фондовыйопцион: " << stock_options << endl;
}

void main(void)

{
   employee worker("ДжонДой", "Программист", 35000);
   manager boss("ДжейнДой", "Вице-президент", "Lexus", 50000.0, 5000, 1000);
   worker.show_employee() ;
   boss.show_manager();
}

Как видите, программа определяет базовый класс employee, а затем определяет производный класс manager. Обратите внимание на конструктор manager. Когда вы порождаете класс из базового класса, конструктор производного класса должен вызвать конструктор базового класса. Чтобы вызвать конструктор базового класса, поместите двоеточие сразу же после конструктора производного класса, а затем укажите имя конструктора базового класса с требуемыми параметрами:

manager::manager(char *name, char *position, char *company_car, float salary, float bonus, int stock_options) :
employee(name, position, salary) //————————————— Конструкторбазовогокласса

{
strcpy(manager::company_car, company_car);
manager::annual_bonus = bonus;
manager::stock_options = stock_options;
}

Также обратите внимание, что функция show_manager вызывает функцию show_employee, которая является элементом класса employee. Поскольку класс manager является производным класса employee, класс manager может обращаться к общим элементам класса employee, как если бы все эти элементы были определены внутри класса manager,

Представление о наследовании

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

Второй пример

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

class book

{
public:
   book (char *, char *, int);
   void show_book(void);
private:
   char title[64];
   char author[б4];
   int pages;
};

Далее предположим, что программе требуется создать класс library_card, который будет добавлять следующие элементы данных в класс book:

char catalog[64];
int checked_out; // 1, еслипроверена, иначеО

Ваша программа может использовать наследование, чтобы породить класс library _card из класса book, как показано ниже:

class library_card : public book

{
public:
   library_card(char *, char *, int, char *, int);
   void show_card(void);
private:
   char catalog[64] ;
   int checked_out;
};

СледующаяпрограммаBOOKCARD.CPP порождаетклассlibrary_card изклacca book:

#include <iostream.h>

#include <string.h>

class book

{
public:
   book(char *, char *, int);
   void show_book(void);
private:
   char title [64];
   char author[64];
   int pages;
};

book::book(char •title, char *author, int pages)

{
   strcpy(book::title, title);
   strcpy(book::author, author);
   book::pages = pages;
}

void book::show_book(void)

{
   cout << "Название: " << title << endl;
   cout << "Автор: " << author << endl;
   cout << "Страниц: " << pages << endl;
}

class library_card : public book

{
public:
   library_card(char *, char *, int, char *, int);
   void show_card(void) ;
private:
   char catalog[64];
   int checked_out;
};

library_card::library_card(char *title, char *author, int pages, char *catalog, int checked_out) : book(title, author, pages)

{
   strcpy(library_card::catalog, catalog) ;
   library_card::checked_out = checked_out;
}

void 1ibrary_card::show_card(void)

{
   show_book() ;
   cout << "Каталог: " << catalog << endl;
   if (checked_out) cout << "Статус: проверена" << endl;
   else cout << "Статус: свободна" << endl;
}

void main(void)

{
   library_card card( "УчимсяпрограммироватьнаязыкеC++", "Jamsa", 272, "101СРР", 1);
   card.show_card();
}

Как и ранее, обратите внимание, что конструктор library _card вызывает конструктор класса book для инициализации элементов класса book. Кроме того, обратите внимание на использование функции-элемента show_book класса book внутри функции show_card. Поскольку класс library_card наследует методы класса book, функция show_card может вызвать этот метод (show_book) без помощи оператора точки, как если бы этот метод был методом класса library _card.

ЧТО ТАКОЕ ЗАЩИЩЕННЫЕ ЭЛЕМЕНТЫ

При изучении определений базовых классов вы можете встретить элементы, объявленные как public, private и protected (общие, частные и защищенные). Как вы знаете, производный класс может обращаться к общим элементам базового класса, как будто они определены в производном классе. С другой стороны, производный класс не может обращаться к частным элементам базового класса напрямую. Вместо этого для обращения к таким элементам производный класс должен использовать интерфейсные функции. Защищенные элементы базового класса занимают промежуточное положение между частными и общими. Если элемент является защищенным, объекты производного класса могут обращаться к нему, как будто он является общим. Для оставшейся части вашей программы защищенные элементы являются как бы частными. Единственный способ, с помощью которого ваши программы могут обращаться к защищенным элементам, состоит в использовании интерфейсных функций. Следующее определение класса book использует метку protected, чтобы позволить классам, производным от класса book, обращаться к элементам title, author и pages напрямую, используя оператор точку:

class book

{
public:
   book(char *, char *, int) ;
   void show_book(void) ;
protected:
   char title [64];
   char author[64];
   int pages;
};

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

Защищенные элементы обеспечивают доступ и защиту

Как вы уже знаете, программа не может обратиться напрямую к частным элементам класса. Для обращения к частным элементам программа должна использовать интерфейсные функции, которые управляют доступом к этим элементам. Как вы, вероятно, заметили, наследование упрощает программирование в том случае, если производные классы могут обращаться к элементам базового класса с помощью оператора точки. В таких случаях ваши программы могут использовать защищенные элементы класса. Производный класс может обращаться к защищенным элементам базового класса напрямую, используя оператор точку. Однако оставшаяся часть вашей программы может обращаться к защищенным элементам только с помощью интерфейсных функций этого класса. Таким образом, защищенные элементы класса находятся между общими (доступными всей программе) и частными (доступными только самому классу) элементами.

РАЗРЕШЕНИЕ КОНФЛИКТА ИМЕН

Если вы порождаете один класс из другого, возможны ситуации, когда имя элемента класса в производном классе является таким же, как имя элемента в базовом классе. Если возник такой конфликт, C++ всегда использует элементы производного класса внутри функций производного класса. Например, предположим, что классы book и library_card используют элемент price. В случае класса book элемент price соответствует продажной цене книги, например $22.95. В случае класса library'_card price может включать библиотечную скидку, например $18.50. Если в вашем исходном тексте не указано явно (с помощью оператора глобального разрешения), функции класса library_card будут использовать элементы производного класса {library_card). Если же функциям класса library_card необходимо обращаться к элементу price базового класса {book), они должны использовать имя класса book и оператор разрешения, например book::price. Предположим, что функции show_card необходимо вывести обе цены. Тогда она должна использовать следующие операторы:

cout << "Библиотечная цена: $" << price << endl;
cout << "Продажная цена: $" << book::price << endl;

ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ

Из этого урока вы узнали, что наследование в C++ позволяет вам строить /порождать) новый класс из существующего класса. Строя таким способом один класс из другого, вы уменьшаете объем программирования, что, в свою очередь, экономит ваше время. Из урока 27 вы узнаете, что C++ позволяет вам порождать класс из двух или нескольких базовых классов. Использование нескольких базовых классов для порождения класса представляет собой множественное наследование. До изучения урока 27 убедитесь, что освоили следующие основные концепции:

14.   

1.      Наследование представляет собой способность производить новый класс из существующего базового класса.

2.      Производный класс — это новый класс, а базовый класс — существующий класс.

3.      Когда вы порождаете один класс из другого (базового класса), производный класс наследует элементы базового класса.

4.      Для порождения класса из базового начинайте определение производного класса ключевым словом class, за которым следует имя класса, двоеточие и имя базового класса, например class dalmatian: dog.

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

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

7.      Чтобы обеспечить производным классам прямой доступ к определенным элементам базового класса, в то же время защищая эти элементы от оставшейся части программы, C++ обеспечивает защищенные {protected) элементы класса. Производный класс может обращаться к защищенным элементам базового класса, как будто они являются общими. Однако для оставшейся части программы защищенные элементы эквивалентны частным.

8.      Если в производном и базовом классе есть элементы с одинаковым именем, то внутри функций производного класса C++ будет использовать элементы производного класса. Если функциям производного класса необходимо обратиться к элементу базового класса, вы должны использовать оператор глобального разрешения, например base class:: member.

Урок 27. Множественное наследование

Из урока 26 вы узнали, что можно построить один класс из другого, наследуя его характеристики. Оказывается, C++ позволяет порождать класс из нескольких базовых классов. Когда ваш класс наследует характеристики нескольких классов, вы используете множественное наследование. Как вы узнаете из данного урока, C++ полностью поддерживает множественное наследование. К концу этого урока вы изучите следующие основные концепции:

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

10.  При множественном наследовании производный класс получает атрибуты двух или более классов.

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

12.  При порождении класса из производного класса вы создаете иерархию наследования (иерархию классов).

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

ПРОСТОЙ ПРИМЕР

Предположим, к примеру, у вас есть класс computer_screen:

class computer_screen

{
public:
   computer_screen(char *, long, int, int);
   void show_screen(void);
private:
   char type[32] ;
   long colors;
   int x_resolution;
   int y_resolution;
};

Предположим, что у вас есть также класс mother_board:

class mother_board

{
public:
   mother_board(int, int, int);
   void show_mother_board(void);
private:
   int processor;
   int speed;
   int RAM;
};

Используя эти два класса, можно породить класс computer, что показано ниже:

class computer : public computer_screen, public mother_board

{
public:
   computer(char *, int, float, char *, long, int, int, int, int, int);
   void show_computer(void);
private:
   char name[64];
   int hard_disk;
   float floppy;
};

Как видите, этот класс указывает свои базовые классы сразу после двоеточия, следующего за именем класса computer.

class computer : public computer_screen, public mother_board // ——————> Базовыеклассы

СледующаяпрограммаCOMPUTER. CPP порождаетклассcomputer, используябазовыеклассыcomputer_screen иmother_board:

#include <iostream.h>

#include <string.h>

class computer_screen

{
public:
   computer_screen(char *, long, int, int);
   void show_screen(void);
private:
   char type[32];
   long colors;
   int x_resolution;
   int y_resolution;
};

computer_screen::computer_screen(char *type, long colors, int x_res, int y_ree)

{
   strcpy(computer_screen::type, type);
   computer_screen::colors = colors;
   computer_screen::x_resolution = x_res;
   computer_screen::y_resolution = y_res;
}

void computer_screen::show_screen(void)

{
   cout << "Типэкрана: " << type << endl;
   cout << "Цветов: " << colors << endl;
   cout << "Разрешение: " << x_resolution << " на" << y_resolution << endl;
}

class mother_board

{
public:
   mother_board(int, int, int);
   void show_mother_board(void);
private:
   int processor;
   int speed;
   int RAM;
};

mother_board::mother_board(int processor, int speed, int RAM)

{
   mother_board::processor = processor;
   mother_board::speed = speed;
   mother_board::RAM = ram;
}

void mother_board::show_mother_board(void)

{
   cout << "Процессор: " << processor << endl;
   cout << "Частота: " << speed << "МГц" << endl;
   cout << "ОЗУ: " << RAM << " МВайт" << endl;
}

class computer : public computer_screen, public mother_board

{
public:
   computer(char *, int, float, char *, long, int, int, int, int, int);
   void show_computerf void);
private:
   char name [64];
   int hard_disk;
   float floppy;
};

computer::computer(char *name, int hard_disk, float floppy, char *screen, long colors, int x_res, int y_res, int processor, int speed, int RAM) : computer_screen(screen, colors, x_res, y_res), mother_board(processor, speed, ram)

{
   strcpy(computer::name, name);
   computer::hard_disk = hard_disk;
   computer::floppy = floppy;
}

void computer::show_computer(void)

{
   cout << "Тип: " << name << endl;
   cout << "Жесткийдиск: " << hard_disk << "МВайт" << endl;
   cout << "Гибкийдиск: " << floppy << "МВайт" << endl;
   show_mother_board();
   show_screen();
}

void main(void)

{
   computer my_pc("Compaq", 212, 1.44, "SVGA", 16000000, 640, 480, 486, 66, 8);
   my_pc.show_computer();
}

Если вы проанализируете конструктор класса computer, то обнаружите, что он вызывает конструкторы классов mother_board и computer_screen, как показано ниже:

computer::computer(char *name, int hard_disk, float floppy, char *screen, long colors, int x_res, int y_res, int processor, int speed, int RAM) : computer_screen(screen, colors, x_res, y_res), mother_board(processor, speed, RAM)

ПОСТРОЕНИЕ ИЕРАРХИИ КЛАССОВ

При использовании наследования в C++ для порождения одного класса из другого возможны ситуации, когда вы порождаете свой класс из класса, который уже, в свою очередь, является производным от некоторого базового класса. Например, предположим, вам необходимо использовать класс сотputer базовый для порождения класса workstation, как показано ниже:

class work_station : public computer

{
public:
   work_station (char *operating_system, char *name, int hard_disk, float floppy, char *screen, long colors, int x_res, int       y_res, int processor, int speed, int RAM);
   void show_work_station(void);
private:
   char operating_system[64];
};

Конструктор класса workstation просто вызывает конструктор класса computer, который в свою очередь вызывает конструкторы классов сотрuter_screen и mother_board:

work_station::work_station( char *operating_system, char *name, int hard_disk, float floppy, char *screen, long colors, int    x_res, int y_res, int processor, int speed, int RAM) : computer (name, hard_disk, floppy, screen, colors, x_res, y_res,    processor, speed, RAM)

{
   strcpy(work_station::operating_system, operating_system);
}

В данном случае класс computer выступает в роли базового класса. Однако вы знаете, что класс computer был порожден из классов computer_screen и mother_board. В результате класс work_station наследует характеристики всех трех классов. На рис. 27 показано, что порождение классов приводит к иерархии классов.

http://programmersclub.ru/27/p27.gif

Рис. 27. Построение иерархии классов.

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

ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ

Множественное наследование представляет собой возможность порождать класс из нескольких базовых классов. При использовании множественного наследования производный класс получает характеристики (элементы) существующих базовых классов. Поддержка множественного наследования в C++ предоставляет вашим программам огромные возможности объектно-ориентированного программирования. Из урока 28 вы узнаете, как обеспечить доступ к частным элементам класса со стороны других классов или функций других классов, которые вы указываете как друзей. Используя таких друзей, вы можете предоставить определенным функциям прямой доступ к элементам класса, одновременно обеспечивая их защиту от остальной части программы. Прежде чем перейти к уроку 28, убедитесь, что вы изучили следующее:

15.  Множественное наследование является способностью порожденного класса наследовать характеристики нескольких базовых классов.

16.  Для порождения класса из нескольких базовых после имени нового класса и двоеточия вы указываете имена базовых классов, разделяя их запятыми, например class cabbit: public cat, public rabbit.

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

18.  При порождении классов может случиться так, что используемый вами базовый класс реально порожден из других базовых классов. Если так, то ваша программа создает иерархию классов. Если вызывается конструктор вашего производного класса, то вызываются также и конструкторы наследуемых классов (последовательно).

Урок 28. Частные элементы и друзья

Как вы уже знаете, ваши программы могут обращаться к частным (private) элементам класса только с помощью функций-элементов этого же класса. Используя частные элементы класса вместо общих во всех ситуациях, где это только возможно, вы уменьшаете возможность программы испортить значения элементов класса, так как программа может обращаться к таким элементам только через интерфейсные функции (которые управляют доступом к частным элементам). Однако в зависимости от использования объектов вашей программы, иногда вы можете существенно увеличить производительность позволяя одному классу напрямую обращаться к частным элементам другого. В этом случае уменьшаются издержки (требуемое время выполнения) на вызов интерфейсных функций. В подобных ситуациях C++ позволяет определить класс в качестве друга (friend} другого класса и разрешает классу-другу доступ к частным элементам этого другого класса. В этом уроке объясняется, как ваши программы могут указать, что два класса являются друзьями. К концу данного урока вы освоите следующие основные концепции:

19.  Используя ключевое слово friend, класс может сообщить C++, кто является его другом, т. е. другими словами, что другие классы могут обращаться напрямую к его частным элементам.

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

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

Частные (private) элементы позволяют вам защищать классы и уменьшить вероятность ошибок. Таким образом, вы должны ограничить использование классов-друзей настолько, насколько это возможно. Иногда программа напрямую может изменить значения элементов класса, это увеличивает вероятность появления ошибок.

ОПРЕДЕЛЕНИЕ ДРУЗЕЙ КЛАССА

C++ позволяет друзьям определенного класса обращаться к частным элементам этого класса. Чтобы указать C++, что один класс является другом (friend) другого класса, вы просто помещаете ключевое слово friend и имя соответствующего класса-друга внутрь определения этого другого класса. Например, приведенный ниже класс book объявляет класс librarian своим другом. Поэтому объекты класса librarian могут напрямую обращаться к частным элементам класса book, используя оператор точку:

class book

{
public:
   book (char *, char *, char *);
   void show_book(void);
   friend librarian;
private:
   char title [64] ;
   char author[64];
   char catalog[64];
};

Как видите, чтобы указать друга, необходим только один оператор внутри определения класса. Например, следующая программа VIEWBOOK.CPP использует librarian в качестве друга класса book. Следовательно, функции класса librarian могут напрямую обращаться к частным элементам класса book. В данном случае программа использует функцию change_catalog класса librarian для изменения номера карточки каталога определенной книги:

#include <iostream.h>

#include <string.h>

class book

{
public:
   book (char *, char *, char *);
   void show_book(void);
   friend librarian;
private:
   char title[64] ;
   char author[64];
   char catalog[64];
};

book::book(char *title, char *author, char •catalog)

{
   strcpy(book::title, title);
   strcpy(book::author, author) ;
   strcpy(book::catalog, catalog);
}

void book::show_book(void)

{
   cout << "Название: " << title << endl;
   cout << "Автор: " << author << endl;
   cout << "Каталог: " << catalog << endl;
}

class librarian

{
public:
   void change_catalog(book *, char *);
   char *get_catalog(book);
};

void librarian::change_catalog(book *this_book, char *new_catalog)

{
   strcpy(this_book->catalog, new_catalog);
}

char *librarian: :get__catalog(book this_book)

{
   static char catalog[64];
   strcpy(catalog, this_book.catalog);
   return(catalog) ;
}

void main(void)

{
   book programming( "УчимсяпрограммироватьнаязыкеC++", "Jamsa", "P101");
   librarian library;
   programming.show_book();
   library.change_catalog(&programming, "ЛегкийC++ 101");
   programming.show_book();
}

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

О друзьях класса

Обычно единственный способ, с помощью которого ваши программы могут обращаться к частным элементам класса, заключается в использовании интерфейсных функций. В зависимости от использования объектов программы иногда может быть удобным (или более эффективным с точки зрения скорости вычислений) разрешить одному классу обращаться к частным элементам другого. Для этого вы должны информировать компилятор C++, что класс является другом (friend). Компилятор, в свою очередь, позволит классу-другу обращаться к частным элементам требуемого класса. Чтобы объявить класс другом, поместите ключевое слово friend и имя класса-друга в секцию public определения класса, как показано ниже:

class abbott

{
public:
friend costello;
//
Общиеэлементы
private:
//
Частныеэлементы
};

Как друзья отличаются от защищенных (protected) элементов

Из урока 26 вы узнали, что в C++ существуют защищенные (protected) элементы класса, что позволяет производным классам обращаться к защищенным элементам базового класса напрямую, используя оператор точку. Помните, что к защищенным элементам класса могут обращаться только те классы, которые являются производными от данного базового класса, другими словами, классы, которые наследуют элементы базового класса (защищенные элементы класса являются как бы частными по отношению к остальным частям программы). Классы-друзья C++ обычно не связаны между собой узами наследования. Единственный способ для таких не связанных между собой классов получить доступ к частным элементам другого класса состоит в том, чтобы этот другой класс информировал компилятор, что данный класс является другом.

ОГРАНИЧЕНИЕ КОЛИЧЕСТВА ДРУЗЕЙ

Как вы только что узнали, если вы объявляете один класс другом другого класса, вы обеспечиваете классу-другу доступ к частным элементам данных этого другого класса. Вы также знаете и то, что чем больше доступа к частным данным класса, тем больше шансов на внесение ошибок в программу. Следовательно, если доступ к частным данным другого класса необходим только нескольким функциям класса, C++ позволяет указать, что только определенные функции дружественного класса будут иметь доступ к частным элементам. Предположим, например, что класс librarian, представленный в предыдущей программе, содержит много разных функций. Однако предположим, что только функциям change_catalog и get_catalog необходим доступ к частным элементам класса book. Внутри определения класса book мы можем ограничить доступ к частным элементам только этими двумя функциями, как показано ниже:

class book

{
public:
   book(char *, char *, char *);
   void show_book(void);
   friend char *librarian::get_catalog(book);
   friend void librarian: :change_catalog( book *, char *);
private:
   char title[64];
   char author[ 64 ];
   char catalog[64];
};

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

О функциях-друзьях

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

public:
friend class_name::function_name(parameter types);

Только функции-элементы, указанные как друзья, могут напрямую обращаться к частным элементам класса, используя оператор точку.

Если ваша программа начинает ссылаться на один класс из другого, вы можете получить синтаксические ошибки, если порядок определения классов неверен. В данном случае определение класса book использует прототипы функций, определенные в классе librarian. Следовательно, определение класса librarian должно предшествовать определению класса book. Однако если вы проанализируете класс librarian, то обнаружите, что он ссылается на класс book:

class librarian

{
public:
   void change_catalog(book *, char *);
   char *get_catalog(book);
};

Поскольку вы не можете поставить определение класса book перед определением класса librarian, C++ позволяет вам объявить класс book, тем самым сообщая компилятору, что такой класс есть, а позже определить его. Ниже показано, как это сделать:

class book; // объявление класса

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

#include <iostream.h>

#include <string.h>

class book;

class librarian

{
public:
   void change_catalog(book *, char *);
   char *get_catalog(book);
};

class book

{
public:
   book(char *, char *, char *) ;
   void show_book (void);
   friend char *librarian::get_catalog(book);
   friend void librarian::change_catalog( book *, char *);
private:
   char title[64];
   char author[64];
   char catalog[64];
};

book::book(char *title, char *author, char *catalog)

{
   strcpy(book::title, title);
   strcpy(book::author, author);
   strcpy(book::catalog, catalog);
}

void book::show_book(void)

{
   cout << "Название: " << title << endl;
   cout << "Автор: " << author << endl;
   cout << "Каталог: " << catalog << endl;
}

void librarian::change_catalog(book *this_book, char *new_catalog)

{
   strcpy(this_book->catalog, new_catalog) ;
}

char *librarian::get_catalog(book this_book)

{
   static char catalog[64];
   strcpy(catalog, this_book.catalog);
   return(catalog) ;
}

void main(void)

{
   book programming( "УчимсяпрограммироватьнаC++", "Jamsa", "P101");
   librarian library;
   programming.show_book();
   library.change_catalog(&programming, "ЛегкийC++ 101");
   programming.show_book();
}

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

Что такое идентификатор класса

Идентификатор представляет собой имя, например имя переменной или класса. Если ваши программы используют дружественные классы, то может случиться, что определение одного класса ссылается на другой класс (его имя или идентификатор), о котором компилятор C++ еще ничего не знает. В таких случаях компилятор C++ будет сообщать о синтаксических ошибках. Чтобы избавиться от ошибок типа "что следует определять сначала", C++ позволяет вам включать в начало исходного текста программы объявление класса, тем самым вводя идентификатор класса:

class class_name;

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

ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ

В данном уроке вы изучили, как использовать классы-друзья для обращения к частным элементам другого класса напрямую с использованием оператора точки. В уроке 29 вы изучите, как использовать в C++ шаблоны функций для упрощения определения подобных функций. Но прежде чем перейти к уроку 29 убедитесь, что вы освоили следующее:

15.   

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

2.      Для объявления одного класса другом (friend) другого класса вы должны внутри определения этого другого класса указать ключевое слово friend, за которым следует имя первого класса.

3.      После объявления класса другом по отношению к другому классу, все функции-элементы класса-друга могут обращаться к частным элементам этого другого класса.

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

5.      При объявлении дружественных функций вы можете получить синтаксические ошибки, если неверен порядок определений классов. Если необходимо сообщить компилятору, что идентификатор представляет имя класса, который программа определит позже, вы можете использовать оператор такого вида class class_name;.

Урок 29. Использование шаблонов функций

При создании функций иногда возникают ситуации, когда две функции выполняют одинаковую обработку, но работают с разными типами данных (например, одна использует параметры типа int, а другая типа float). Вы уже знаете из урока 13, что с помощью механизма перегрузки функций можно использовать одно и то же имя для функций, выполняющих разные действия и имеющих разные типы параметров. Однако, если функции возвращают значения разных типов, вам следует использовать для них уникальные имена (см. примечание к уроку 13). Предположим, например, что у вас есть функция с именем тах, которая возвращает максимальное из двух целых значений. Если позже вам потребуется подобная функция, которая возвращает максимальное из двух значений с плавающей точкой, вам следует определить другую функцию, например fmax. Из этого урока вы узнаете, как использовать шаблоны C++ для быстрого создания функций, возвращающих значения разных типов. К концу данного урока вы освоите следующие основные концепции:

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

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

8.      Шаблоны функций имеют специфичные имена, которые соответствуют имени функции, используемому вами в программе.

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

10.  В процессе компиляции компилятор C++ будет создавать в вашей программе функции с использованием типов, указанных в прототипах функций, которые ссылаются на имя шаблона.

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

СОЗДАНИЕ ПРОСТОГО ШАБЛОНА ФУНКЦИИ

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

template<class Т> Тmах(Та, Тb)

{
   if (а> b) return(а);
   else return(b);
}

Буква T данном случае представляет собой общий тип шаблона. После определения шаблона внутри вашей программы вы объявляете прототипы функций для каждого требуемого вам типа. В случае шаблона тах следующие прототипы создают функции типа float и int.

float max(float, float);
int max(int, int);

Когда компилятор C++ встретит эти прототипы, то при построении функции он заменит тип шаблона T указанным вами типом. В случае с типом float функция тах после замены примет следующий вид:

template<class Т> Тmax(Та, Тb)

{
   if (a > b) return(а) ;
   else return(b);
}

float max(float a, float b)

{
   if (a > b) return(a) ;
   else return(b);
}

Следующая программа МАХ_ТЕМР.СРР использует шаблон тах для создания функции типа int и float.

#include <iostream.h>

template<class T> Тmах(Та, Тb)

{
   if (a > b) return(a);
   else return(b);
}

float max(float, float);

int max(int, int);

void main(void)

{
   cout << "Максимум100 и200 равен" << max(100, 200) << endl;
   cout << "Максимум5.4321 и1.2345 равен" << max(5.4321, 1.2345) << endl;
}

В процессе компиляции компилятор C++ автоматически создает операторы для построения одной функции, работающей с типом int, и второй функции, работающей с типом float. Поскольку компилятор C++ управляет операторами, соответствующими функциям, которые вы создаете с помощью шаблонов, он позволяет вам использовать одинаковые имена для функций, которые возвращают значения разных типов. Вы не смогли бы это сделать, используя только перегрузку функций, как обсуждалось в уроке 13.

Использование шаблонов функций

По мере того как ваши программы становятся более сложными, возможны ситуации, когда вам потребуются подобные функции, выполняющие одни и те же операции, но с разными типами данных. Шаблон функции позволяет вашим программам определять общую, или типонезависимую, функцию. Когда программе требуется использовать функцию для определенного типа, например int или float, она указывает прототип функции, который использует имя шаблона функции и типы возвращаемого значения и параметров. В процессе компиляции C++ создаст соответствующую функцию. Создавая шаблоны, вы уменьшаете количество функций, которые должны кодировать самостоятельно, а ваши программы могут использовать одно и то же имя для функций, выполняющих определенную операцию, независимо от возвращаемого функцией значения и типов параметров.

ШАБЛОНЫ, КОТОРЫЕ ИСПОЛЬЗУЮТ НЕСКОЛЬКО ТИПОВ

Предыдущее определение шаблона для функции max использовало единственный общий тип Т. Очень часто в шаблоне функции требуется указать несколько типов. Например, следующие операторы создают шаблон для функции show_array, которая выводит элементы массива. Шаблон использует тип Т для определения типа массива и тип Т1 для указания типа параметра count:

template<class T,class T1> void show_array(T *array,T1 count)

{
   T1 index;
   for (index =0; index < count; index++) cout << array[index] << ' ';
   cout << endl;
}

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

void show_array(int *, int);
void show_array(float *, unsigned);

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

#include <iostream.h>

template<class T,class T1> void show_array( T *array,T1 count)

{
   T1 index;
   for (index =0; index < count; index++) cout << array[index] “ ' ';
   cout << endl;
}

void show_array(int *, int);

void show_array(float *, unsigned);

void main(void)

{
   int pages[] = { 100, 200, 300, 400, 500 };
   float pricesH = { 10.05, 20.10, 30.15 };
   show_array(pages, 5);
   show_array(prices, 3);
}

Шаблоны и несколько типов

По мере того как шаблоны функций становятся более сложными, они могут обеспечить поддержку нескольких типов. Например, ваша программа может создать шаблон для функции с именем array_sort, которая сортирует элементы массива. В данном случае функция может использовать два параметра: первый, соответствующий массиву, и второй, соответствующий количеству элементов массива. Если программа предполагает, что массив никогда не будет содержать более 32767 значений она может использовать тип int для параметра размера массива. Однако более универсальный шаблон мог бы предоставить программе возможность указать свой собственный тип этого параметра, как показано ниже:

template<class Т, class T1> void array_sort(T array[], T1 elements)

{
// операторы
}

С помощью шаблона array_sort программа может создать функции которые сортируют маленькие массивы типа float (менее 128 элементов) и очень большие массивы типа int, используя следующие прототипы:

void array_sort(float, char);
void array_sort(int, long);

ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ

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

16.   

1.      Шаблоны функций позволяют вам объявлять типонезависимые, или общие, функции.

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

3.      Когда компилятор C++ встретит такой прототип функции, он создаст операторы, соответствующие этой функции, подставляя требуемые типы.

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

5.      Если функция требует несколько типов, шаблон просто назначает каждому типу уникальный идентификатор, например Т, T1 и Т2. Позже в процессе компиляции компилятор C++ корректно назначит типы, указанные вами в прототипе функции.

Урок 30. Использование шаблонов классов

Из урока 29 вы узнали, как в C++ использовать шаблоны функций для создания общих, или типонезависимых, функций. Определяя шаблоны функций вы заставляете компилятор C++ создавать в случае необходимости функции, которые отличаются типом возвращаемого значения или типами параметров. Если возникает необходимость создавать подобные функции, отличающиеся только используемыми типами, то может возникнуть необходимость и создания общих классов. А если так, то ваши программы могут определять шаблоны классов. В этом уроке рассмотрены действия вашей программы, необходимые для объявления и дальнейшего использования шаблонов классов. К концу данного урока вы освоите следующие основные концепции:

6.      Используя ключевое слово template и символы типов (например, Т, T1 и Т2) ваши программы могут создать шаблон класса — определение шаблона класса может использовать эти символы для объявления элементов данных, указания типов параметров и возвращаемого значения функций-элементов и т.д.

7.      Для создания объектов класса с использованием шаблонов ваши программы просто ссылаются на имя класса, за которым внутри угловых скобок следуют типы (например, <int, float>), каждому из которых компилятор назначает символы типов и имя переменной.

8.      Если у класса есть конструктор, с помощью которого вы инициализируете элементы данных, вы можете вызвать этот конструктор при создании объекта с использованием шаблона, например class_name<int,float>values(200);.

9.      Если компилятор C++ встречает объявление объекта, он создает класс из шаблона, используя соответствующие типы.

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

СОЗДАНИЕ ШАБЛОНА КЛАССА

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

class array

{
public:
   array(int size);
   long sum(void);
   int average_value(void);
   void show_array(void);
   int add_value(int);
private:
   int *data;
   int size;
   int index;
};

Следующая программа I_ARRAY.CPP использует класс array ддя работы со значениями типа int.

#include <iostream.h>

#include <stdlib.h>

class array

{
public:
   array(int size);
   long sum(void);
   int average_value(void);
   void show_array(void);
   int add_value(int) ;
private:
   int *data;
   int size;
   int index;
};

array::array(int size)

{
   data = new int [size];
   if (data == NULL)

{
      cerr << "Недостаточно памяти - программа завершается " << endl;
      exit(l);
   }

array:: size = size;
   array::index = 0;
}

long array::sum(void)

{
   long sum = 0;
   for (int i = 0; i < index; i++) sum += data[i];
   return(sum);
}

int array::average_value(void)

{
   long sum = 0;
   for (int i = 0; i < index; i++) sum += data[i];
   return (sum / index);
}

void array::show_array(void)

{
   for (int i = 0; i < index; i++) cout << data[i] << ' ';
   cout << endl;
}

int array::add_value(int value)

{
   if (index == size) return(-1); // массивполон
   else

{
      data[index] = value;
      index++;
      return(0); // успешно
   }
}

void main(void)

{
   array numbers (100); // массивиз100 эл-тов
   int i;
   for (i = 0; i < 50; i++) numbers.add_value(i);
   numbers.show_array();
   cout << "Суммачиселравна" << numbers.sum () << endl;
   cout << "Среднеезначениеравно" << numbers.average_value() << endl;
}

Как видите, программа распределяет 100 элементов массива, а затем заносит в массив 50 значений с помощью метода add_value. В классе array переменная index отслеживает количество элементов, хранимых в данный момент в массиве. Если пользователь пытается добавить больше элементов, чем может вместить массив, функция add_value возвращает ошибку. Как видите, функция average_value использует переменную index для определения среднего значения массива. Программа запрашивает память для массива, используя оператор new, который подробно рассматривается в уроке 31.

Шаблоны классов

По мере того как количество создаваемых вами классов растет, вы обнаруживаете, что некоторый класс, созданный для одной программы (или, возможно, для этой), очень похож на требующийся вам сейчас. Во многих случаях классы могут отличаться только типами. Другими словами, один класс работает с целочисленными значениями, в то время как требующийся вам сейчас должен работать со значениями типа. float. Чтобы увеличить вероятность повторного использования существующего кода, C++ позволяет вашим программам определять шаблоны классов. Если сформулировать кратко, то шаблон класса определяет типонезависимый класс, который в дальнейшем служит для создания объектов требуемых типов. Если компилятор C++ встречает объявление объекта, основанное на шаблоне класса, то для построения класса требуемого типа он будет использовать типы, указанные при объявлении. Позволяя быстро создавать классы, отличающиеся только типом, шаблоны классов сокращают объем программирования, что, в свою очередь, экономит ваше время.

Пойдем дальше. Теперь предположим, что вашей программе необходимо работать с массивом значений с плавающей точкой, кроме того, что она работает с целочисленным массивом. Один из способов обеспечить поддержку массивов различных типов состоит в создании разных классов. С другой стороны, используя шаблоны классов, вы можете избавиться от необходимости дублировать классы. Ниже представлен шаблон класса, который создает общий класс array:

template<class T, class T1> class array

{
public:
   array(int size);
   T1 sum (void);
   T average_value(void);
   void show_array(void);
   int add_value(T);
private:
   T *data;
   int size;
   int index;
};

Этот шаблон определяет символы типов T и T1. В случае массива целочисленных значений Т будет соответствовать int, а T1 — long. Аналогичным образом для массива значений с плавающей точкой значения Т и Т1 равны float. Теперь потратьте время, чтобы убедиться, что вы поняли, как компилятор С++ будет подставлять указанные вами типы вместо символов Т и Т1.

Далее, перед каждой функцией класса вы должны указать такую же запись со словом template. Кроме того, сразу же после имени класса вы должны указать типы класса, например array <T, T1>::average_value. Следующий оператор иллюстрирует определение функции average_value для этого класса:

template<class Т, class T1> Тarray<T, T1>::average_value(void)

{
   T1 sum = 0;
   int i;
   for (i = 0; i < index; i++) sum += data[i] ;
   return (sum / index);
}

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

Имяшаблона//----> array <int, long> numbers (100); <------//Типышаблона
                                     array <float, float> values(200);

Программа GENARRAY.CPP использует шаблон класса array для создания двух классов, один из которых работает со значениями типа int, а второй — со значениями типа float.

#include <iostream.h>

#include <stdlib.h>

template<class T, class T1> class array

{
public:
   array(int size);
   T1 sum(void);
   T average_value(void);
   void show_array(void);
   int add_value(T);
private:
   T *data;
   int size;
   int index;
};

template<class T, class T1> array<T, t1>::array(int size)

{
   data = new T[size];
   if (data == NULL)

{
      cerr << "Недостаточно памяти - программа завершается" << endl;
      exit(l);
   }

array::size = size;
   array::index = 0;
}

template<class T, class T1> Tl array<T, Tl>::sum(void)

{
   T1 sum = 0;
   for (int i = 0; i < index; i++) sum += data[i];
   return(sum);
}

template<class T, class T1> T array<T, T1>::average_value(void)

{
   Tl sum =0;
   for (int i = 0; i < index; i++) sum += data[i];
   return (sum / index);
}

template<class T, class T1> void array<T, T1>::show_array(void)

{
   for (int i = 0; i < index; i++) cout << data[i] << ' ';
   cout << endl;
}

template<class T, class T1> int array<T, T1>::add_value(T value)

{
   if (index == size)
   return(-1); // Массивполон
   else

{
      data[index] = value;
      index++;
      return(0); // Успешно
   }
}

void main(void)

{
   // Массивиз100 элементов
   array<int, long> numbers(100)7
   // Массивиз200 элементов
   array<float, float> values(200);
   int i;
   for (i = 0; i < 50; i++) numbers.add_value(i);
   numbers.show_array();
   cout << "Суммачиселравна" << numbers.sum () << endl;
   cout << "Среднеезначениеравно" << numbers.average_value() << endl;
   for (i = 0; i < 100; i++) values.add_value(i * 100);
   values.show_array();
   cout << "Суммачиселравна." << values.sum() << endl;
   cout << "Среднеезначениеравно" << values.average_value() << endl;
}

Лучшим способом понять шаблоны классов будет напечатать две копии этой программы. В первой копии замените все символы T и Т1 на int и long. A во второй замените Т и Т1 на float.

Объявление объектов, основанных на шаблоне класса

Для создания объектов с использованием шаблона класса вы просто должны указать имя шаблона класса, за которым между левой и правой угловыми скобками укажите типы, которыми компилятор заменит символы Т, T1, T2 и т. д. Затем ваша программа должна указать имя объекта (переменной) со значениями параметров, которые вы хотите передать конструктору класса, как показано ниже:

template_class_name<typel, type2> object_name( parameter1, parameter2);

Когда компилятор C++ встречает такое объявление, он создает класс, основанный на указанных типах. Например, следующий оператор использует шаблон класса array для создания массива типа char, в котором хранится 100 элементов:

array<char, int> small_numbers(100) ;

ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ

Из этого урока вы узнали, что шаблоны классов помогут вам избавиться от дублирования кода программы, если вам необходимы объекты похожих классов, которые отличаются только типом. Поскольку шаблоны классов могут быть сложными, они могут вас смутить. Когда вы определяете ваш класс, начните с определения, как будто бы вы создаете класс для конкретного типа. После того как вы полностью опишете класс, определите какие элементы необходимо изменить, чтобы работать с объектами различных типов. Теперь замените типы этих элементов такими символами, как, например, Т, Т1, Т2 и т.д.

17.   

1.      Программы, представленные в данном уроке, использовали оператор C++ new для динамического (во время выполнения программы) распределения памяти для массива. В уроке 31 вы подробно ознакомитесь с оператором new. Прежде чем перейти к уроку 31, убедитесь, что вы изучили следующее:

2.      Шаблоны классов позволяют избавиться от дублирования кода для таких классов, чьи объекты отличаются только типом их элементов.

3.      Для создания шаблона класса предварите определение класса ключевым словом template и символами типов, например Т и T1.

4.      Далее вы должны предварить определение каждой функции класса таким же оператором с ключевым словом template. Кроме того, укажите типы шаблона между левой и правой угловыми скобками, а выражение в угловых скобках поместите между именем класса и оператором разрешения области видимости, например class_name<T,T1>::function_name.

5.      Для создания класса с использованием шаблона укажите имя класса и замещающие значения для типов между левой и правой угловыми скобками, например class_name<int, long> object.


Смотреть видео онлайн


Смотреть русское с разговорами видео

Online video HD

Видео скачать на телефон

Русские фильмы бесплатно

Full HD video online

Смотреть видео онлайн

Смотреть HD видео бесплатно

School смотреть онлайн