Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Tankist 90
0 / 0 / 2
Регистрация: 27.04.2015
Сообщений: 273
#1

Параметр шаблона класса как собственный тип данных - C++

29.04.2017, 00:14. Просмотров 419. Ответов 21
Метки нет (Все метки)

Приветствую. Такой вопрос: как перегрузить операторы класса-шаблона, где в качестве аргумента шаблона выступает собственный тип данных. Если приведёте примеры кода - буду премного благодарен.
http://www.cyberforum.ru/cpp-beginners/thread762217.html
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
29.04.2017, 00:14
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Параметр шаблона класса как собственный тип данных (C++):

Свой тип как параметр шаблона
Есть вопрос по коду: #include <iostream> #include <memory> #include <vector>...

Как ограничить параметр типа шаблона только числовыми типами данных?
Собствено, сабж. Ключевое для поиска слово хотябы.

Как узнать тип данных шаблона функции?
Я старался делать так: #include<iostream> #include<fstream> #include<conio.h>...

Как сделать функцию, которая тип данных использует как параметр?
Хочу сделать функцию function("переменные", "тип данных"). Можно ли это...

Собственный тип данных в deque
Добрый день. Возникла проблема. Надо очистить объект и вписать значения....

21
GoldenId
131 / 130 / 64
Регистрация: 11.11.2010
Сообщений: 770
Записей в блоге: 14
Завершенные тесты: 1
29.04.2017, 00:20 #2
std::greater
Оно?
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
7002 / 3295 / 448
Регистрация: 04.12.2011
Сообщений: 9,117
Записей в блоге: 5
29.04.2017, 01:30 #3
Цитата Сообщение от Tankist 90 Посмотреть сообщение
как перегрузить операторы класса-шаблона, где в качестве аргумента шаблона выступает собственный тип данных.
Перегрузка операций для шаблона это вещь бессмысленная. Шаблон должен использовать операции которые нужны для реализации его алгоритмов. А операции, должны быть перегружены у типов которые передаются шаблону. Разумеется, они должны быть перегружены в соответствии с семантикой шаблона, иначе их туда лучше не передавать.
0
Tankist 90
0 / 0 / 2
Регистрация: 27.04.2015
Сообщений: 273
29.04.2017, 11:42  [ТС] #4
Цитата Сообщение от IGPIGP Посмотреть сообщение
операции, должны быть перегружены у типов которые передаются шаблону
Т.е. если я передаю в шаблон класса параметр являющийся новым типом данных, я должен перегрузить все использующиеся в классе-шаблоне операторы в теле передаваемого класса?
0
Croessmah
++Ͻ
14147 / 8072 / 1512
Регистрация: 27.09.2012
Сообщений: 19,910
Записей в блоге: 3
Завершенные тесты: 1
29.04.2017, 11:45 #5
Tankist 90, если честно, не очень понятно что Вы имеете ввиду.

C++
1
2
3
4
5
6
7
8
9
10
template<typename T>
class Some
{
//...
public:
   Some operator+(const Some &rhv)
   {
      //...
   }
};
1
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
7002 / 3295 / 448
Регистрация: 04.12.2011
Сообщений: 9,117
Записей в блоге: 5
29.04.2017, 11:57 #6
Цитата Сообщение от Tankist 90 Посмотреть сообщение
я должен перегрузить все использующиеся в классе-шаблоне операторы в теле передаваемого класса?
иначе получите ошибку компиляции когда попробуете инстанцировать. Покажите кусочек кода, поскольку есть неоднозначность в Вашем вопросе. Посмотрите вопрос Croessmah. Он намекает на то, что и шаблон может перегрузить операции. Причём пользовательсий (или не пользовательский) тип - параметр шаблона, строго говоря, может и не перегружать ничего подобного. В этом случае семантика, как правило, не будет соблюдаться, но формально это реализуемо. Например, при сложении заставить пользовательский тип спеть Соловья Алябьева вместо сложения. Если он умеет конечно.
Если пользовательский тип имеет метод вроде T add(const &T, const T&) например, то можно и неперегружая + в T сохранить семантику при перегрузке + в шаблоне. Хотя изврат наверное. Покажите, что Вы имеете ввиду.
0
Tankist 90
0 / 0 / 2
Регистрация: 27.04.2015
Сообщений: 273
29.04.2017, 12:06  [ТС] #7
Цитата Сообщение от IGPIGP Посмотреть сообщение
Покажите кусочек кода
Шаблонный класс:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
template <class T>
class Set
{
 
  int g; //переменная для хранения размерности
  T *mas;// для создания массива
 
public:
 
    Set(){}//конст. без парам.
 
    Set(int a)// с параметром
    {
        g=a;
 
        mas=new T[g];// создаём массив
        for(int i=0;i<g;i++)// заполнием нулями
        {
           mas[i]=0;
        }
    }
 
    Set(Set&ob){}// конст. копирования
    
 
    void set()// функц. заполнения массива из консоли
    {
      cout<<"Введите массив:\n";
      for(int i=0;i<g;i++)// заполняем
      {
        cin>>mas[i];
      }
    }
//----------------------------------------//
    Set operator* (Set <T>& ob)// перегрузка для *
    {
      Set <T> t(g);
      int k=0;
 
      for(int i=0;i<g;i++)
      {
          for(int j=0;j<g;j++)
          {
            if(mas[i]==ob.mas[j])//если массивы равны...
            {
              t.mas[k++]=mas[i];//... записать в новый
              break;
            }
          }
      }
      if(k!=0){
          for(int i=0;i<k;i++)
              cout<<"\nсовпадениe  обнаружено:"<<t.mas[i]<<endl;
      }else cout<<"\nсовпадений не обнаружено..."<<endl; 
 
        return t;
    }
friend istream& operator>>(istream &s, T ob )//перегрузка для >>
{ 
    s>>ob;
    return s;
}
 
friend ostream& operator<<(ostream &s, T ob)//перегрузка для <<
{
    s<<ob;
  return s;
}
 
};
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
class e//собственный тип передав. в кач. парам. шаблона
{
public:
   e& operator=(int a)//перегрузка для =
   {
     // что-то пишем 
   }
 
  const bool& operator==(e& ob)//перегрузка для ==
   {
      // что-то пишем
   }
};
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
7002 / 3295 / 448
Регистрация: 04.12.2011
Сообщений: 9,117
Записей в блоге: 5
29.04.2017, 12:13 #8
Цитата Сообщение от Tankist 90 Посмотреть сообщение
Set(Set&ob){}// конст. копирования
Это плохо! Нужно бы выделить в копии память так как это делает конструктор с целым параметром и потом скопировать туда элементы. Иначе первая же перадача в функцию завалит программу. И параметр по конст ссылке передайте.
Что касается перегрузки операторов для шаблона<Т> то она должна бы быть тут наименее зависима от возможностей T.
0
Tankist 90
0 / 0 / 2
Регистрация: 27.04.2015
Сообщений: 273
29.04.2017, 12:47  [ТС] #9
Цитата Сообщение от IGPIGP Посмотреть сообщение
Нужно бы выделить в копии память так как это делает конструктор с целым параметром и потом скопировать туда элементы
Можно на примере? Просто мы почти не работали с конструкторами копирования. Просто пишем их как элемент класса и всё...

Добавлено через 28 минут
Вы имели в виду что-то вроде этого:
C++
1
2
3
4
5
6
7
8
Set(const Set&ob)
{
  mas=new T[ob.g];// создаём массив
        for(int i=0;i<ob.g;i++)// заполняем нулями
        {
           mas[i]=0;
        } 
}
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
7002 / 3295 / 448
Регистрация: 04.12.2011
Сообщений: 9,117
Записей в блоге: 5
29.04.2017, 13:19 #10
Цитата Сообщение от Tankist 90 Посмотреть сообщение
Вы имели в виду что-то вроде этого:
Да. Только размер получаете у оригинала, потом копируете не нули а соответственно элементы.
Что касается операторов, то можно как угодно, но я считаю, что потребность диктует клиент. Пусть клиентами шаблона являются числовые типы : int, /...и пр. int/, float, double, long double и Вы делаете класс для работы с векторами (мат) на этих типах. То есть Вам нужно складывать, считать векторное и скалярное произведения и пр. Тогда Вам не нужно реализовывать операции на типах клиентах. Они уже есть. А операция сложения на типе - шаблоне будет пользоваться операциями для типов - параметров (клиентов). Хотя если говорить только о этой операции, то передача параметром типа string не вызовет ошибки, хотя семантически будет не верной. Но если вы создали шаблон для сцепления строк, то бессмысленно будет передавать числовые типы. В C++ Bы не можете конкретизировать тип предложением вроде were T is int, float, double и имеет смысл перегружать операторы вроде сложения в контексте потребностей клиента. Наделять клиента такой способностью лишь для дальнейшей перегрузки в шаблоне бессмысленно. Потребность должна диктоваться от Вашего пользовательского класса. В принципе таких классов нужно бы иметь группу либо такой класс должен поддерживать семантику для группы уже существующих типов. Иначе зачем шаблон? Какие типы он будет обобщать?

Добавлено через 8 минут
Цитата Сообщение от IGPIGP Посмотреть сообщение
Что касается перегрузки операторов для шаблона<Т> то она должна бы быть тут наименее зависима от возможностей T.
Это полностью противоречит сказанному выше. Но это потому, что как я понял тогда Ваш Set - аналог множества и не имеет ничего общего с мат операциями над своим типом. То есть, вообще то о чём Вы спрашиваете зависит от того что Вы намерены сделать.
0
Tankist 90
0 / 0 / 2
Регистрация: 27.04.2015
Сообщений: 273
29.04.2017, 13:40  [ТС] #11
C++
1
2
3
4
5
6
7
8
Set(const Set&ob)
{
  mas=new T[ob.g];// создаём массив
        for(int i=0;i<ob.g;i++)
        {
           mas[i]=ob.mas[i]; //?
        } 
}
Собственно, вот задание:
1. Создать шаблон заданного класса. Определить конструкторы, деструктор, перегруженную операцию присваивания
(“=”) и операции, заданные в варианте задания.
2. Написать программу тестирования, в которой проверяется использование шаблона для стандартных типов данных.
3. Выполнить тестирование.

Первых три пункта я выполнил давно и они работали прекрасно. А вот далее и возникли проблемы:

4. Определить пользовательский класс, который будет использоваться в качестве параметра шаблона. Определить в классе необходимые функции и перегруженные операции.
5. Написать программу тестирования, в которой проверяется использование шаблона для пользовательского типа.
6. Выполнить тестирование.
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
7002 / 3295 / 448
Регистрация: 04.12.2011
Сообщений: 9,117
Записей в блоге: 5
29.04.2017, 16:11 #12
Tankist 90, теперь конструктор копии адекватен. В деструкторе не забудьте delete [] mass;
оператор присваивания должен возвращать ссылку (на себя *this). Сначала проверяем this==&obj и если да то уходим. Иначе проверяем g==obj.j если да то просто копируем из объекта g элементов (все то есть). если нет, то освобождаем память по указателю и выделяем и копируем по новой. Эта часть аналогична той что в конструкторе копии и поэтому имеет смыл написать отдельный метод вроде того что:
C++
1
2
3
4
5
6
7
void init (const Set&ob) {
mas=new T[obj.g]; 
        for(int i=0;i<ob.g;i++)
        {
           mas[i]=ob.mas[i]; //?
        } 
}
и вызывать его как в конструктор, так и в оператор =
0
Croessmah
++Ͻ
14147 / 8072 / 1512
Регистрация: 27.09.2012
Сообщений: 19,910
Записей в блоге: 3
Завершенные тесты: 1
29.04.2017, 16:17 #13
IGPIGP, не совсем корректен. g забыли скопировать.
1
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
7002 / 3295 / 448
Регистрация: 04.12.2011
Сообщений: 9,117
Записей в блоге: 5
29.04.2017, 17:44 #14
Цитата Сообщение от Croessmah Посмотреть сообщение
IGPIGP, не совсем корректен. g забыли скопировать.
Где? Я написал что если g равны то просто копируем g элементов, а если нет то удаляем и делаем снова как в конструкторе копии. А там g копируется. Хотя это тоже можно бы в предложенный init интегрировать.
Но в конструкторе копии нет ничего вроде g=obj.g это да.
0
Tankist 90
0 / 0 / 2
Регистрация: 27.04.2015
Сообщений: 273
30.04.2017, 15:38  [ТС] #15
Цитата Сообщение от IGPIGP Посмотреть сообщение
оператор присваивания
Можете на примере показать, как правильно перегрузить operator= в моём случае?
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
7002 / 3295 / 448
Регистрация: 04.12.2011
Сообщений: 9,117
Записей в блоге: 5
30.04.2017, 16:06 #16
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
using namespace std; 
template <class T>
class Set
{
 
  int g; //переменная для хранения размерности
  T *mas;// для создания массива
 
public:
 
    Set():g(0), mass(nullptr){ }//конст. без парам.
    ~Set(){g=0; delete [] mass; }
 
    Set(int a)// с параметром
    {
        g=a;
 
        mas=new T[g];// создаём массив
        for(int i=0;i<g;i++)// заполнием нулями
        {
           mas[i]=0;
        }
    }
 
void init(const Set & ob){
 
g=ob.g;
mas=new T[g];// создаём массив
        for(int i=0;i<g;i++)// заполнием нулями
        {
           mas[i]= ob.mas[i];
        }
 
 
    }
    Set(const Set & ob){
     init (ob); 
    }// конст. копирования
    
  Set & operator=(const Set & ob){
    if(this == &ob) return *this;
        if(ob.g==g)init(ob);
            else{
                delete []mass;                   
                        init(ob);
}
            return *this;
  }
   
 
};
1
Tankist 90
0 / 0 / 2
Регистрация: 27.04.2015
Сообщений: 273
30.04.2017, 16:34  [ТС] #17
Эта запись:
Цитата Сообщение от IGPIGP Посмотреть сообщение
C++
1
Set():g(0), mass(nullptr)
Можете пояснить...
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
7002 / 3295 / 448
Регистрация: 04.12.2011
Сообщений: 9,117
Записей в блоге: 5
30.04.2017, 20:57 #18
Цитата Сообщение от Tankist 90 Посмотреть сообщение
Можете пояснить...
Тут допускается возможность создать по умолчанию не инициализированный объект. Кому-то может показаться страшно, но дело вкуса. Просто создавая объект нужно помнить, что по умолчанию он пуст. Зато создавая массив или вектор, скажем, таких объектов, Вы не будете выделять память дважды. Там используется конструктор по умолчанию и можно создать "пачку" пустых объектов, а потом присвоить так как нужно. При этом память под каждый объект будет выделяться один раз. А обнуления указателя (а тем более счётчика) можно и не делать, конечно. Просто, удаление освобождение нулевого, ничем никому не грозит. Если захочется то можно проверить на ноль... Но в целом, можете оставить так как у Вас. При взгляде на код не будет видно ничего и два таких конструктора для разных классов будут неотличимы. С военно-конспирологической точки зрения очень удобно, опять же.
1
Tankist 90
0 / 0 / 2
Регистрация: 27.04.2015
Сообщений: 273
30.04.2017, 21:41  [ТС] #19
IGPIGP, исправил код. Выдаёт следующую ошибку:
error C2679: бинарный "=": не найден оператор, принимающий правый операнд типа "int" (или приемлемое преобразование отсутствует)
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
7002 / 3295 / 448
Регистрация: 04.12.2011
Сообщений: 9,117
Записей в блоге: 5
30.04.2017, 21:53 #20
Там утечку памяти я нарисовал. То есть если g==ob.g всё равно перевыделение, да ещё и без освобождения. В общем, выделение из init убрать если, то получается лучше.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void init(){
 
        for(int i=0;i<g;i++)//
        {
           mas[i]= 0;
        }
 
 
    }
    void init(const Set & ob){
        for(int i=0;i<g;i++)//
        {
           mas[i]= ob.mas[i];
        }
    }
 
Set(int a)// с параметром
    {
        g=a; 
        mas=new T[g];// создаём массив
        init();
    }
 
    Set(const Set & ob){
g=ob.a; 
        mas=new T[g];// создаём массив
            init (ob);  
    }// конст. копирования
 
     
  Set & operator=(const Set & ob){
    if(this == &ob) return *this;
        if(ob.g==g)init(ob);
            else{
                delete []mass;
g=ob.a; 
        mas=new T[g];
                    init(ob);
}
            return *this;
  }
Добавлено через 2 минуты
Цитата Сообщение от Tankist 90 Посмотреть сообщение
error C2679: бинарный "=": не найден оператор, принимающий правый операнд типа "int" (или приемлемое преобразование отсутствует)
Это потому видимо что для класса оператор присвоения перегружен, а для int нет. Или у пользовательского класса нет перегрузки =, а шаблон по ссылке от индексного обращение целое в него тычет. Покажите строчку которую компилятор проклял.
0
30.04.2017, 21:53
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
30.04.2017, 21:53
Привет! Вот еще темы с решениями:

Как передать параметр в собственный манипулятор с параметром?
Ребята, вопрос, вот задача: Создать манипулятор endp(n), задающим...

Как создать свой собственный тип на C++?
Здравствуйте!!! Возник вопрос как создать свой собственный тип на С++ который...

Передача функции как параметр шаблона
Хочу передавать в шаблон любую функцию без параметров и вызывать ее из него....


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru