Листинг 18.4. Использование оператора вывода



1: #include <iostream.h>

2:

3: const int DefaultSize = 10;

4:

5: class Animal

6: {

7: public:

8: Animal(int);

9: Animal();

10: ~Animal() { }

11: int GetWeight() const { return itsWeight; }

12: void Display() const { cout << itsWeight; }

13: private:

14: int itsWeight;

15: };

16:

17: Animal::Animal(int weight):

18: itsWeight(weight)

19: { }

20:

21: Animal::Animal():

22: itsWeight(0)

23: { }

24:

25: template <class T> // объявляем шаблон и параметр

26: class Array // параметризованный класс

27: {

28: public:

29: // конструкторы

30: Array(int itsSize = DefaultSize);

31: Array(const Array &rhs);

32: ~Array() { delete [] pType; }

33:

34: // операторы

35: Array& operator=(const Array&);

36: T& operator[](int offSet) { return pType[offSet]; }

37: const T& operator[](int offSet) const

38: { return pType[offSet]; }

39: // методы доступа

40: int GetSize() const { return itsSize; }

41:

42: friend ostream& operator<< (ostream&, Array<T>&);

43:

44: private:

45: T *pType;

46: int itsSize;

47: };

48:

49: template <class T>

50: ostream& operator<< (ostream& output, Array<T>& theArray)

51: {

52: for (int i = 0; i<theArray.GetSize(); i++)

53: output << "[" << i << "] " << theArray[i] << endl; return output;

54: }

55:

56: // Ряд выполнений...

57:

58: // выполнение конструктора

59: template <class T>

60: Array<T>::Array(int size):

61: itsSize(size)

62: {

63: pType = new T[size];

64: for (int i = 0; i<size; i++)

65: pType[i] = 0;

66: }

67:

68: // конструктор-копировщик

69: template <class T>

70: Array<T>::Array(const Array &rhs)

71: {

72: itsSize = rhs.GetSize();

73: pType = new T[itsSize];

74: for (int i = 0; i<itsSize; i++)

75: pType[i] = rhs[i];

76: }

77:

78: // перегрузка оператора присваивания (=)

79: template <class T>

80: Array<T>& Array<T>::operator=(const Array &rhs)

81: {

82: if (this == &rhs)

83: return *this;

84: delete [] pType;

85: itsSize = rhs.GetSize();

86: pType = new T[itsSize];

87: for (int i = 0; i<itsSize; i++)

88: pType[i] = rhs[i];

89: return *this;

90: }

91:

92: int main()

93: {

94: bool Stop = false; // признак для цикла

95: int offset, value;

96: Array<int> theArray;

97:

98: while (!Stop)

99: {

100: cout << "Enter an offset (0-9) ";

101: cout << "and a value. (-1 to stop): ";

102: cin >> offset >> value;

103:

104: if (offset < 0)

105: break;

106:

107: if (offset > 9)

108: {

109: cout << "***Please use values between 0 and 9.***\n";

110: continue;

111: }

112:

113: theArray[offset] = value;

114: }

115:

116: cout << "\nHere's the entire array:\n";

117: cout << theArray << endl;

118: return 0;

119: }

 

Результат:

Enter an offset (0 -9 and а value. (-1 to stop) 1 10

Enter an offset (0 -9 and а value. (-1 to stop) 2 20

Enter an offset (0 -9 and а value. (-1 to stop) 3 30

Enter an offset (0 -9 and а value. (-1 to stop) 4 40

Enter an offset (0 -9 and а value. (-1 to stop) 5 50

Enter an offset (0 -9 and а value. (-1 to stop) 6 60

Enter an offset (0 -9 and а value. (-1 to stop) 7 70

Enter an offset (0 -9 and а value. (-1 to stop) 8 80

Enter an offset (0 -9 and а value. (-1 to stop) 9 90

Enter an offset (0 -9 and а value. (-1 to stop) 1С 10

***Please use values between 0 and 9.* >>*

Enter an offset (0 -9) and а value. (-1 to stop) -1 -1

Here's the entire array:

[0] 0

[1] 10

[2] 20

[3] 30

[4] 40

[5] 50

[6] 60

[7] 70

[8] 80

[9] 90

 

Анализ: В строке 42 объявляется шаблон функции operator<<() в качестве друга шаблона класса Array. Поскольку operator<<() реализован в виде функции шаблона, то каждый экземпляр этого типа параметризованного массива будет автоматически иметь функцию operator<<() для вывода данных соответствующего типа. Выполнение этого оператора начинается в строке 49. Каждый член массива вызывается по очереди. Этот метод работает только в том случае, если функция operator<<() определена для каждого типа объекта, сохраняемого в массиве.

 

 

Использование экземпляров шаблона

 

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

Листинг 19.5. Передача в функцию экземпляра шаблона

1: #include <iostream.h>

2:

3: const int DefaultSize = 10;

4:

5: // Обычный класс, из объектов которого будет состоять массив

6: class Animal

7: {

8: public:

9: // конструкторы

10: Animal(int);

11: Animal();

12: ~Animal();

13:

14: // методы доступа

15: int GetWeight() const { return itsWeight; }

16: void SetWeight(int theWeight) { itsWeight = theWeight; }

17:

18: // дружественные операторы

19: friend ostream& operator<< (ostream&, const Animal&);

20:

21: private:

22: int itsWeight;

23: };

24:

25: // оператор вывода объектов типа Animal

26: ostream& operator<<

27: (ostream& theStream, const Animal& theAnimal)

28: {

29: theStream << theAnimal.GetWeight();

30: return theStream;

31: }

32:

33: Animal::Animal(int weight):

34: itsWeight(weight)

35: {

36: // cout << "Animal(int)\n";

37: }

38:

39: Animal::Animal():

40: itsWeight(0)

41: {

42: // cout << "Animal()\n";

43: }

44:

45: Animal::~Animal()

46: {

47: // cout << "Destroyed an animal...\n";

48: }

49:

50: template <class T> // объявление шаблона и параметра

51: class Array // параметризованный класс

52: {

53: public:

54: Array(int itsSlze = DefaultSize);

55: Array(const Array &rhs);

56: ~Array() { delete [] pType; }

57:

56: Array& operator=(const Array&);

59: T& operator[](int offSet) { return pType[offSet]; }

60: const T& operator[](int offSet) const

61: { return pType[offSet]; }

62: int GetSize() const { return itsSize; }

63:

64: // функция-друг

65: friend ostream& operator<< (ostream&, const Array<T>&);

66:

67: private:

68: T *рТуре;

69: int itsSize;

70: };

71:

70: template <class T>

72: ostream& operator<< (ostream& output, const Array<T>& theArray)

73: {

74: for (int i = 0; i<theArray.GetSize(); i++)

75: output << "[" << i << "] " << theArray[i] << endl;

76: return output;

77: }

78:

79: // Ряд выполнений...

80:

81: // выполнение конструктора

82: template <class T>

83: Array<T>::Array(int size):

84: itsSize(size)

85: {

86: рТуре = new T[size];

67: for (int i = 0; i<size; i++)

88: pType[i] = 0;

89: }

90:

91: // конструктор-копировщик

92: template <class T>

93: Array<T>::Array(const Array &rhs)

94: {

95: itsSize = rhs.GetSize();

96: рТуре = new T[itsSize];

97: for (int i = 0; i<itsSize; i++)

98: pType[i] = rhs[i];

99: }

100:

101: void IntFillFunction(Array<int>& theArray);

102: void AnimalFillFunction(Array<Animal>& theArray);

103:

104: int main()

105: {

106: Array<int> intArray;

107: Array<Animal> animalArray;

108: IntFillFunction(intArray);

109: AnimalFillFunction(animalArray);

110: cout << "intArray...\n" << intArray;

111: cout << "\nanimalArray...\n" << aninalArray << endl;

112: return 0;

113: }

114:

115: void IntFillFunction(Array<int>& theArray)

116: {

117: bool Stop = false;

118: int offset, value;

119: while (!Stop)

120: {

121: cout << "Enter an offset (0-9) ";

122: cout << "and a value, (-1 to stop): " ;

123: cin >> offset >> value;

124: if (offset < 0)

125: break;

126: if (offset > 9)

127: {

128: cout << "***Please use values between 0 and 9.***\n";

129: continue;

130: }

131: theArray[offset] = value;

132: }

133: }

134:

135:

136: void AnimalFillFunction(Array<Animal>& theArray)

137: {

138: Animal * pAnimal;

139: for (int i = 0; i<theArray,GetSize(); i++)

140: {

141: pAnimal = new Animal;

142: pAnimal->SetWeight(i*100);

143: theArray[i] = *pAnimal;

144: delete pAnimal; // копия была помещена в массив

145: }

146: }

 

Результат:

Enter an offset (0- 9) and а value. ( -1 to stop) 1 10

Enter an offset (0- 9) and а value. ( -1 to stop) 2 20

Enter an offset (0- 9) and а value. ( -1 to stop) 3 30

Enter an offset (0- 9) and а value. ( -1 to stop) 4 40

Enter an offset (0- 9) and а value. ( -1 to stop) 5 50

Enter an offset (0- 9) and а value. ( -1 to stop) 6 60

Enter an offset (0- 9) and а value. ( -1 to stop) 7 70

Enter an offset (0- 9) and а value. ( -1 to stop) 8 80

Enter an offset (0- 9) and а value. ( -1 to stop) 9 90

Enter an offset (0-9) and а value. ( -1 to stop) 10 10

***Please use values between 0 and 9.***

Enter an offset (0-9) and a value. (-1 to stop): -1 -1

intArray:... [0] 0 [1] 10 [2] 20

[3] 30

[4] 40

[5] 50

[6] 60

[7] 70

[8] 80

[9] 90

animalArray:...

[0] 0

[1] 100

[2] 200

[3] 300

[4] 400

[5] 500

[6] 600

[7] 700

[8] 800

[9] 900

 

Анализ: В целях экономии места большая часть выполнения класса Array не показана в этом листинге. Класс Animal объявляется в строках 6—23. И хотя структура этого класса предельно упрощена, тем не менее в нем содержится собственный оператор вывода (<<), позволяющий выводить на экран объекты массива типа Animal.

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

В строке 101 объявляется функция IntFillFunction(), параметром которой является целочисленный массив. Обратите внимание, что эта функция не принадлежит шаблону, поэтому может принять только массив целочисленных значений. Аналогичным

образом в строке 102 объявляется функция AnimalFillFunction(), которая принимает массив объектов типа Animal.

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

Специализированные функции

 

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

При добавлении объекта в массив вызывается стандартный конструктор объекта. Однако конструктор класса Array также используется для присвоения нулевых значений каждому члену массива, как показано в строках 59 и 60 листинга 19.2.

В выражении someAnimal = (Animal) 0; вызывается стандартный оператор operator= для класса Animal. Это приводит к созданию временного объекта Animal с помощью конструктора, который принимает целое число (нуль). Этот временный объект выступает правым операндом в операции присваивания, после чего удаляется деструктором.

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

Эта идея реализована в листинге 19.6 путем явного выполнения класса Animal.


Дата добавления: 2019-02-12; просмотров: 206; Мы поможем в написании вашей работы!

Поделиться с друзьями:






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