Файл: Pobegaylo_A._C_Cplus_dlya_studenta.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 13.12.2020

Просмотров: 4322

Скачиваний: 28

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Часть II. Язык программирования С++ 

256 

Не  разрешается  объявлять  шаблонами  виртуальные  функции-

члены  класса.  Это  обусловлено  тем,  что  возникают  проблемы  с 

построением таблицы виртуальных функций. Так как в этом слу-

чае при обработке определения класса компилятор не может оп-

ределить  количество  виртуальных  функций  класса,  которые  бу-

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

виртуальной  функции-члена  класса  в  производном  классе  не  за-

мещает  соответствующую  виртуальную  функцию-член  базового 

класса.  Это  происходит  потому,  что  компилятор  добавляет  к 

имени  шаблонной  функции  типы  аргументов,  для  которых  эта 

функция специализирована. 
В листинге 18.13 показано, что шаблонная функция производного 

класса не замещает виртуальную функцию базового класса. 

Листинг 18.13. Определение шаблона функции  

в производном классе 

#include <iostream> 
using namespace std; 

class Base 

public: 
  virtual int foo(const int &n) { return n; } 
}; 
class Derived: public Base 

public: 
  template <class T> T foo(const T &t) { return 2*t; } 
}; 

int main() 

  Derived d; 
  Base* b = &d; 

  cout << b->foo(10) << endl;  // печатает: 10 
  cout << d.foo(10) << endl;   // печатает: 20 

  return 0; 


background image

  

 
 

Г Л А В А  

19 

 
 
 

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

 

19.1. Определение шаблона класса 

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

родовым

  или 

обобщенным 

(generic)

  классом

.  

В  языке  программирования  С++  родовые  классы  определяются 

шаблонами классов

. Определение шаблона класса имеет следую-

щий вид: 

  template <список_параметров> 
  определение_класса 

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

Box

,  предназначенного  для  хранения  значения  определенного 

типа 

T

, который является параметром шаблона класса. Используя 

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

  

 


background image

Часть II. Язык программирования С++ 

258 

Листинг 19.1. Определение шаблона класса 

Box

 

template <class T> class Box 

  bool empty;  // состояние контейнера 
  T    room;   // место для хранения значения 
public: 
  Box(): empty(true) {} 
  void put(T a);   // положить значение в контейнер 
  T    get();      // извлечь значение из контейнера 
  bool isEmpty() const;  // проверить, свободен ли контейнер 
}; 
 
template <class T> void Box<T>::put(T a) 

  room = a; 
  empty = false; 

template <class T> T Box<T>::get() 

  empty = true; 
  return room; 

template <class T> bool Box<T>::isEmpty() const 

  return empty; 

В листинге 19.2 приведен пример шаблона контейнерного класса 

Stack

,  предназначенного  для  хранения  значений  определенного 

типа 

T

,  который  является  параметром  шаблона  класса.  Размер-

ность стека задается целочисленным параметром 

n

 шаблона клас-

са. Конечно, параметр для задания размерности стека можно бы-

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

ров шаблона. 

Листинг 19.2. Шаблон класса 

Stack

 

template <class T, int n> class Stack 

  int size;  // размер стека 


background image

Глава 19. Шаблоны классов 

259 

  int top;   // верхушка стека 
  T* a;      // указатель на массив 
public: 
  Stack(): size(n), top(0), a(new int[size]) {} 
  ~Stack() { delete[] a; } 
 
  void push(const T& n) { a[top++] = n; } 
  void pop(T& n) { n = a[--top]; } 
 
  bool isEmpty() const { return !top; } 
  bool isFull() const { return top == size; } 
}; 

Параметром  шаблона  класса  может  быть  также  шаблон  класса. 
Использование шаблонов класса в качестве параметров шаблонов 
классов будет рассмотрено в 

разд. 19.12

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

19.2. Конкретизация шаблона  

класса 

Процесс создания определения класса из шаблона класса называ-
ется 

конкретизацией

 или 

инстанциированием 

(instantiation)

 шаб-

лона класса

. Класс, созданный из шаблона, называется 

специали-

зацией  шаблона класса

  или 

шаблонным классом

. Шаблон класса 

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

Box

,  определенного  в  листинге  19.1.  Предполагается,  что 

определение  этого  шаблона  хранится  в  заголовочном  файле 
Box.h. 

Листинг 19.3. Конкретизация шаблона класса 

Box

 

#include "Box.h" 
#include <iostream> 
using namespace std; 


background image

Часть II. Язык программирования С++ 

260 

int main() 

  // объект для хранения целого числа 
  Box<int> n; 
  n.put(10); 
  cout << n.isEmpty() << endl; 
  cout << n.get() << endl; 
  cout << n.isEmpty() << endl; 
 
  // объект для хранения числа с плавающей точкой 
  Box<double> m; 
  m.put(5.5); 
  cout << m.isEmpty() << endl; 
  cout << m.get() << endl; 
  cout << m.isEmpty() << endl; 
 
  return 0; 

В листинге 19.4 приведен пример конкретизации шаблона класса 

Stack

, определенного в листинге 19.2. Предполагается, что опре-

деление этого шаблона хранится в заголовочном файле Stack.h. 

Листинг 19.4. Конкретизация шаблона класса 

Stack

 

#include "Stack.h" 
#include <iostream> 
using namespace std; 
 
int main() 

  int n; 
  Stack<int, 2> s;  // стек для хранения двух целых чисел 
  cout << s.isEmpty() << ' ' << s.isFull() << endl; 
  s.push(10); 
  s.push(20); 
  cout << s.isEmpty() << ' ' << s.isFull() << endl; 
  s.pop(n); 
  cout << n << endl; 
  s.pop(n); 


Смотрите также файлы