Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.67/54: Рейтинг темы: голосов - 54, средняя оценка - 4.67
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
1

Абстрактный шаблонный класс

26.09.2010, 03:22. Показов 10831. Ответов 45
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Вообщем какое дело. У меня есть класс матрица, который сделан с использованием шаблонов и STL. В нем перегружены операторы ввода/вывода в поток(то, что их не врубить в динамический полиморфизм я уже понял).

Первый класс:

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
    //Класс матрицы
    template<class T>
    class Matr
    {
    public:
       Matr();
       Matr(size_t n, size_t m);
       Matr(const Matr&);
       virtual ~Matr();
       void SetSize(size_t n, size_t m);
       const size_t GetRow() const {return Matrix.size();}
       const size_t GetCol() const {return Matrix[0].size();}
       template<class T2>
       friend std::ostream& operator <<(std::ostream& os, const Matr<T2>& Ob);
       template<class T2>
       friend std::istream& operator >>(std::istream& is, Matr<T2>& Ob);
       Matr<T>& operator =(const Matr&);
       Matr<T> operator +=(const Matr&);
       Matr<T> operator +(const Matr&);
       Matr<T> operator *=(const Matr&);
       Matr<T> operator *(const Matr&);
       void random_fill();
    protected:
       std::vector<std::vector<T> > Matrix;
    };
Определение функций писать не буду, пока это не нужно. Вряд ли 200 строк чем-то помогут. Виртуальными эту перегрузку не сделать. И если я пишу второй код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
template<class T>
class ConsoleMatr:public Matr<T>
{
public:
   ConsoleMatr():Matr() {}
   ConsoleMatr(size_t n, size_t m):Matr(n, m) {}
   ConsoleMatr(const Matr& Ob):Matr(Ob) {}
   template<class T2>
   friend std::ostream& operator <<(std::ostream& os, const ConsoleMatr<T2>& Ob);
   template<class T2>
   friend std::istream& operator >>(std::istream& is, ConsoleMatr<T2>& Ob);
};
И комментирую эти методы в исходном классе, то как реализовать динамический полиморфизм?

Пробую так.
C++
1
2
3
4
5
6
7
8
typedef std::auto_ptr<Matr<int> > MatrSP;
 
int main()
{
   MatrSP Ob(new ConsoleMatr);
   std::cin>>Ob;
   //
}
Пишет ошибку. Впринципе это понятно. Тогда вопрос, как реализовать??

А так же есть вариант оставить оба варианта. Но будут вызываться операторы ввода/вывода из класса Matr.

И следующий вопрос. Добавляю в первый класс две чисто виртуальные функции. Класс принимает вид:

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
    //Класс матрицы
    template<class T>
    class Matr
    {
    public:
       Matr();
       Matr(size_t n, size_t m);
       Matr(const Matr&);
       virtual ~Matr();
       void SetSize(size_t n, size_t m);
       const size_t GetRow() const {return Matrix.size();}
       const size_t GetCol() const {return Matrix[0].size();}
       template<class T2>
       friend std::ostream& operator <<(std::ostream& os, const Matr<T2>& Ob);
       template<class T2>
       friend std::istream& operator >>(std::istream& is, Matr<T2>& Ob);
       Matr<T>& operator =(const Matr&);
       Matr<T> operator +=(const Matr&);
       Matr<T> operator +(const Matr&);
       Matr<T> operator *=(const Matr&);
       Matr<T> operator *(const Matr&);
       void random_fill();
           virtual void input()=0;
           virtual void output()=0;
    protected:
       std::vector<std::vector<T> > Matrix;
    };
А второй.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template<class T>
class ConsoleMatr:public Matr<T>
{
public:
   ConsoleMatr():Matr() {}
   ConsoleMatr(size_t n, size_t m):Matr(n, m) {}
   ConsoleMatr(const Matr& Ob):Matr(Ob) {}
   template<class T2>
   friend std::ostream& operator <<(std::ostream& os, const ConsoleMatr<T2>& Ob);
   template<class T2>
   friend std::istream& operator >>(std::istream& is, ConsoleMatr<T2>& Ob);
   void input();
   void output();
};
Вот так впринципе вполне неплохо идет полиморфизм. Но есть одно НО...

Ошибка происходит в этой функции.

C++
1
2
3
4
5
6
7
    template<class T>
    Matr<T> Matr<T>::operator *(const Matr<T> &Ob)
    {
          Matr<T> Obj(*this);   
          Obj*=Ob;
          return Obj;
    }
Нельзя инстанцинировать абстрактный класс... Что тоже понятно... Но непонятно, как тогда это реализовать. Или же забить на это и оставить как есть?
1
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
26.09.2010, 03:22
Ответы с готовыми решениями:

Указатель на абстрактный шаблонный класс
Есть абстрактный шаблон класса и 3 производных от него шаблонов классов. Так же есть шаблонная...

Класс: Разработать абстрактный класс класс Point для задания координаты...
Всем привет, помогите пожалуйста решить задачу, я уже всю голову сломал, не знаю как решить... ...

Класс Matrix: реализовать шаблонный класс для двумерных массивов
Доброго времени суток. У меня вопрос: я создал класс Array со внутренним динамическим массивом и...

Шаблонный класс и класс одномерный массив
Задание: протестировать класс шаблон, с обычными типами данных я понял как делать, а как передать в...

45
бжни
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
26.09.2010, 03:50 2
C++
1
MatrSP Ob(new ConsoleMatr<int>)
вродеж как

Добавлено через 3 минуты
Цитата Сообщение от Lavroff Посмотреть сообщение
Нельзя инстанцинировать абстрактный класс... Что тоже понятно... Но непонятно, как тогда это реализовать. Или же забить на это и оставить как есть?
никак или объявить виртуальным
2
Эксперт С++
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
26.09.2010, 03:53 3
у меня один вопрос: задача в том, чтоб реализовать операторы ввода-вывода для типа "Т" ?
1
бжни
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
26.09.2010, 03:56 4
auto_ptr - бяка
C++
1
2
3
4
5
6
#include <boost/shared_ptr.hpp>
typedef boost::shared_ptr<Matr<int> > MatrSP;
 
int main(){
    MatrSP sp( new ConsoleMatr<int> );
}
2
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
26.09.2010, 03:56  [ТС] 5
alex_x_x, Да) Так и было написано. А тут забыл(
auto_ptr конечно бяка, но сказали, если использовать указатели использовать именно его. У нас ребята и от этого офигевают чуть более чем полностью. Препод буст нам решил пока не давать.
ЗЫ: объявить виртуальным в каком смысле? Сам класс? Или виртуальное наследование?

niXman, Задача, чтобы разделить класс. На реализацию и собственно консольный ввод/вывод, дабы сам класс Matr мог быть актуален на любой платформе. То есть не только в консольных, но и в других. Должно быть сделано с использованием STL и шаблонов.
1
Эксперт С++
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
26.09.2010, 04:00 6
т.е. ты хочешь сделать так, чтоб ввод-вывод можно было использовать не только из/в консоли, а к примеру, и из файла/сокета?
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
26.09.2010, 04:02  [ТС] 7
niXman, Скорее хочу сделать так, чтобы реализация этих методов не зависила от остального класса, если это пригодится. Каждый ввод в свой класс. Пока у меня стоит задача только консольного ввода-вывода. Препод нам на таком примере объясняет концепции ООП впринципе.
1
Эксперт С++
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
26.09.2010, 04:13 8
Цитата Сообщение от Lavroff Посмотреть сообщение
чтобы реализация этих методов не зависила от остального класса
что-то ты напутал...
класс - шаблонный.
перегруженные операторы - шаблонные. в добавок, еще и дружественные функции этого класса
ну намешал...

объясни, что требуется?

Добавлено через 1 минуту
наверное я не уловил гениальность твоей идеи
1
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
26.09.2010, 04:15  [ТС] 9
niXman, Не моей. Препод попросил так сделать.

Вообщем...

У нас есть класс. Допустим тот же Matr. Шаблонный. В нем есть ввод/вывод в поток (консольный). Попросили сделать так, чтобы от Matr был производный шаблонный класс, в котором и реализуются ввод/вывод на консоль. Это реально? Если нет, то по какой причине, если да, то каким образом. Или не пытаться реализовать эту идею вцелом?
0
84 / 57 / 8
Регистрация: 07.08.2010
Сообщений: 185
26.09.2010, 04:17 10
Ты задал два разных вопроса.

Первый ты уже похоже разрешил. Только я бы сделал вот так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
template<class T2>
std::ostream& operator <<(std::ostream& os, const Matr<T2>& Ob)
{
    Ob.output(os);
    return os;
}
 
template<class T2>
std::istream& operator >>(std::istream& is, Matr<T2>& Ob)
{
    Ob.input(is);
    return is;
}
Соответственные виртуальные функции - input(istream &) и output(ostream &). Никаких френдов не надо. И определять operator<< и >> для ColsoleMatr тоже не надо.

Второй вопрос достаточно интересен. Начнём с того, что возвратить по-значению абстрактный класс ты не сможешь. А операторы принципиально возвращают по-значению, поэтому нужно что-то менять.

Решается это через идиому handle/body. Идея такая:
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
class MatrBase  // абстракный
{
public:
    virtual ~MatrBase() = 0 {}
 
    virtual
    MatrBase * clone() const = 0;  // клонируем себя
 
    void mult_op(MatrBase const * other)
    {
        // умножить *this на *other используя интерфейс MatrBase
    }
};
 
class ConsoleMatr : public MatrBase  // конкретный
{
public:
    ConsoleMatr * clone() const
    {
        return new ConsoleMatr(*this);
    }
};
 
class Matr  // handle
{
public:
    Matr(MatrBase * body) : m_body(body) {}
    ~Matr() { delete m_body; }
 
    Matr operator*(Matr const & other) const
    {
        MatrBase * product = other.m_body->clone();
        product->mult_op(m_body);
        return Matr(product);
    }
private:
    MatrBase * m_body;
};
1
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
26.09.2010, 04:29  [ТС] 11
alexzak, Красиво.
Первый вариант очень понравился.

Второй - тоже гуд, однако несколько не улыбает с этим настолько морочиться, т.к. это учебная программа и мои одногруппники лучше чем у меня была сделана в этот раз не сделают. Им итак надо за неделю понять стл, шаблоны, виртуальные функции, наследование и само ООП вообщем. Другое дело, что это действительно интересно. Надо будет запомнить об этой идиоме.
Я так понимаю ее приблизительный смысл - использование включения(или композиции, не совсем могу понять что из этого тут используется). У нас есть абстрактный класс, есть производный от абстрактного (который и есть главная задача реализовать), а так же есть класс в который входят указатели на объекты абстрактного класса и действие производится в основном через этот класс. Верно?
0
84 / 57 / 8
Регистрация: 07.08.2010
Сообщений: 185
26.09.2010, 04:46 12
handle - это тот класс, с которым мы оперируем по-значению, как с обычными неполиморфным классом. Только так мы можем реализовать невиртуальные операторы умножения и т.д. А body - это полиморфный объект, с которым мы оперируем через указатель на базовый класс.

Это не композиция. Это скорее разделение интерфейса и реализации. Интерфейс здесь - это невиртуальный operator*. А реализация - это метод mult_op. (В данном случае он невиртуальный из-за простоты задачи. А мог бы быть, будь задача посложнее.)
1
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
26.09.2010, 04:57  [ТС] 13
alexzak, Относительно понял. А возможно это сделать не прибегая к паттернам? Виртуальными функциями или же какими-нибудь танцами с бубном? Просто интересно
0
84 / 57 / 8
Регистрация: 07.08.2010
Сообщений: 185
26.09.2010, 05:09 14
Цитата Сообщение от Lavroff Посмотреть сообщение
А возможно это сделать не прибегая к паттернам?
Проблема фундаментального характера. Если Matr абстрактный, то по значению его возвратить нельзя. Но если сделать его конкретным, то можно реализовать operator* как в классе Matr, так и в классе ConsoleMatr:
C++
1
2
3
4
5
6
7
8
9
Matr Matr::operator*(Matr const & rhs) const
{
    // умножаем *this на rhs, оба одного типа, Matr
}
 
ConsoleMatr ConsoleMatr::operator*(ConsoleMatr const & rhs) const
{
    // умножаем *this на rhs, оба одного типа, ConsoleMatr
}
1
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
26.09.2010, 05:17  [ТС] 15
alexzak, Если Matr будет конкретный - я не особо вижу смысла переопределять операторы в производном классе. Перегруженные операторы ведь наследуются, а в данном случае оператор умножения матриц не изменится в любом случае. Ибо это стабильная формула. В чем смысл перегрузки оператора * для ConsoleMatr?
0
84 / 57 / 8
Регистрация: 07.08.2010
Сообщений: 185
26.09.2010, 05:21 16
Цитата Сообщение от Lavroff Посмотреть сообщение
В чем смысл перегрузки оператора * для ConsoleMatr?
Как тогда ты сделаешь такое:
C++
1
2
3
ConsoleMatr m1;
ConsoleMatr m2;
ConsoleMatr m3 = m1 * m2;
1
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
26.09.2010, 05:25  [ТС] 17
alexzak, А для чего? Если для этого - вижу смысл, но, я собираюсь пользоваться дин. полиморфизмом, через auto_ptr<Matr<int> >;
Следовательно объекты будут типа Matr, но выделена под них память будет под тип ConsoleMatr.
C++
1
std::auto_ptr<Matr<int> > Ob(new ConsoleMatr<int>);
0
84 / 57 / 8
Регистрация: 07.08.2010
Сообщений: 185
26.09.2010, 05:29 18
Цитата Сообщение от Lavroff Посмотреть сообщение
C++
1
std::auto_ptr<Matr<int> > Ob(new ConsoleMatr<int>);
Как ты такие объекты собираешься умножать?
C++
1
2
3
std::auto_ptr<Matr<int> > Ob(new ConsoleMatr<int>);
std::auto_ptr<Matr<int> > Ob2(new ConsoleMatr<int>);
std::auto_ptr<Matr<int> > Ob3 = ???
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
26.09.2010, 05:40  [ТС] 19
alexzak,
C++
1
2
std::auto_ptr<Matr<int> > Ob3(new ConsoleMatr<int>);
*Ob3=*Ob1 * *Ob2;
Что-то вроде такого. Хотя голова ща уже не особо хорошо думает.

Добавлено через 8 минут
Как пример:
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
template<class T>
class Int
{
public:
    Int(){a=5;}
    virtual void input(){}
    virtual void output(){}
    Int<T> operator+(const Int<T>& Ob)
    {
        Int Temp;
        Temp.a=a+Ob.a;
        return Temp;
    }
protected:
    T a;
};
 
template<class T>
class ConsoleInt:public Int<T>
{
public:
    ConsoleInt():Int() {}
    void input()
    {
        std::cin>>a;
    }
    void output()
    {
        std::cout<<a<<'\n';
    }
};
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <memory>
 
#include "xfd.h"
 
int main()
{
    std::auto_ptr<Int<int> > Ob(new ConsoleInt<int>);
    Ob->input();
    Ob->output();
    std::auto_ptr<Int<int> > Ob2(new ConsoleInt<int>);
    Ob2->input();
    Ob2->output();
    std::auto_ptr<Int<int> > Ob3(new ConsoleInt<int>);
    *Ob3=*Ob+*Ob2;
    Ob3->output();
    return 0;
}
0
84 / 57 / 8
Регистрация: 07.08.2010
Сообщений: 185
26.09.2010, 05:44 20
В выражении '*Ob3 = *Ob1 * *Ob2' не только operator* должен возвратить результать по-значению, что возможно только если 1) оба класса Matr и ConsoleMatr - конкретные, 2) для каждого из них определён operator* возвращающий значение правильного типа. Но и operator= должен быть виртуальным (тип выражения *Ob3 - Matr&, а не ConsoleMatr&), что само по себе уже странно. А невиртуальный operator= сделает slicing, т.е. он присвоит в объекте Ob3 только часть из базового Matr, но не весь ConsoleMatr. В общем вся объектная модель С++ ломается.
1
26.09.2010, 05:44
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.09.2010, 05:44
Помогаю со студенческими работами здесь

Разработать абстрактный класс класс Point для задания координаты
Народ, не буду врать на подобии &quot;помогите, не понимаю как сделать&quot; и т.п., говорю как есть, у меня...

Класс: Создать абстрактный базовый класс Figure с виртуальными методами вычисления площади и периметра.
Создать абстрактный базовый класс Figure с виртуальными методами вычисления площади и периметра....

Абстрактный класс, наследование, класс хранится в другом классе
Нужна помощь. Написать программу: 1 класс. Имеется абстрактный класс который описывает какую-то...

Переделать класс в шаблонный класс
Как данный процесс проделать? Я попробовал так по синтаксису из учебника: #include &lt;iostream&gt;...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru