Шаблон класса для работы с массивами из элементов любых скалярных типов данных
Код пытается ответить на следующие странные для нормального человека, но жизненно важные для юного программиста вопросы:
- как сделать шаблон класса для работы с массивами из элементов любого скалярного типа данных
<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 просмотра]