БлогNot. Шаблон класса для работы с массивами из элементов любых скалярных типов данных

Шаблон класса для работы с массивами из элементов любых скалярных типов данных

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

  • как сделать шаблон класса для работы с массивами из элементов любого скалярного типа данных <T>
  • как вызвать из шаблона конструктора без аргументов шаблон конструктора с аргументом; правильно - только списком инициализации, пожалуй, см. C() : C(10) { }
  • как генерировать исключения с помощью макроса assert из <cassert>, накладывая ограничения на нужные параметры методов, в том числе, конструкторов;
  • как переопределить оператор [] в шаблоне класса массива для нормального обращения к элементам любого скалярного типа данных через квадратные скобки
  • как при этом создать объект класса "целиком в куче" (большого смысла не имеет, так как динамические свойства, такие как a, всё равно получают память в "куче" при выделении её оператором new) - см. C <float> *f = new C <float> (size) - но, с другой стороны, как вы ещё создадите на этих операторах контейнер с размерностью, заданной через переменную, а не через константу?

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

Проверено в консоли Visual Studio 2019.

/*
 Шаблон класса для работы с массивами из элементов
 любых скалярных типов данных
*/
#include <iostream>
#include <cassert>
using namespace std;

template <typename T> class C {
 //Шаблон класса с подстановкой типа данных T
 T* a;
 int n; //Приватные данные класса
public:
 C() : C(10) { } //Конструктор 1, по умолчанию 10 элементов
 /*
 Если выносить тело конструктора за операторные скобки класса,
 то здесь опишем только прототип:
 C();
 а за операторными скобками класса реализуем шаблон конструктора:
 template <typename T> C <T> ::C() : C <T> (10) { }
 */

 C(int n) { //Конструктор 2, элементов - сколько запросим 
  assert(n > 0); //требования к аргументу n
  a = new T[n];
  assert(a);
  this->n = n;
  for (int i = 0; i < n; i++) a[i] = (T)0;
 }

 ~C() { //Деструктор
  if (a) { delete[] a; a = nullptr; }
 }

 T & operator [] (const int i) {
  //Для нормального обращения к элементам переопределим []
  assert(i > -1 && i < n); //Индекс д.б. допустимым!
  return a[i];
 }
  
 void print(const char* hdr = nullptr) { //Вывод массива в консоль
  if (hdr) cout << hdr;
  for (int i = 0; i < n; i++) cout << a[i] << " ";
  cout << endl;
 }
}; //class C

//Теперь мы можем делать массивы с разным типом элементов одним кодом!

int main() {
 C <int> c; //создаем с размерностью по умолчанию (10)
 c.print(); //печатаем массив
 c[5] = 5;  //изменяем элемент
 c.print(); //печатаем изменённый массив

 C <double> d(5); //создаем массив из 5 вещественных значений
 d[4]++; //изменяем элемент
 //d[6] = 6; //сработает исключение - выход за границу массива!
 d.print("Double array: ");

 C <char> e(3); //создаем массив из 3 символов
 e[0] = e[2] = 'A';
 e.print("Char array: ");
 //delete &e; //падение программы - new же не было"!

 int size = 4;
 C <float> *f = new C <float> (size);
  //Динамический массив со статическими свойствами (такими, как n) в "куче"
  //Контейнер a в любом случае хранится в "куче"
 (*f)[0] = (*f)[1] = (*f)[2] = (*f)[3] = (float)1.5;
 f->print();
 delete f;

 cin.get(); return 0;
}

17.02.2020, 22:07 [1193 просмотра]


теги: учебное программирование c++

К этой статье пока нет комментариев, Ваш будет первым