Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 35, средняя оценка - 4.83
ForEveR
В астрале
Эксперт С++
7994 / 4753 / 321
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
#1

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

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

Вообщем какое дело. У меня есть класс матрица, который сделан с использованием шаблонов и 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
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
26.09.2010, 03:22
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Абстрактный шаблонный класс (C++):

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

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

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

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

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

шаблонный класс - C++
реализован согласно &quot;Создание конструкторов и деструктора&quot; на шаблон класса с параметром -Тип данных в файле, редактируется (байт / слово /...

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

Добавлено через 3 минуты
Цитата Сообщение от Lavroff Посмотреть сообщение
Нельзя инстанцинировать абстрактный класс... Что тоже понятно... Но непонятно, как тогда это реализовать. Или же забить на это и оставить как есть?
никак или объявить виртуальным
2
niXman
Эксперт С++
3139 / 1451 / 49
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
26.09.2010, 03:53 #3
у меня один вопрос: задача в том, чтоб реализовать операторы ввода-вывода для типа "Т" ?
1
alex_x_x
бжни
2454 / 1660 / 84
Регистрация: 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
ForEveR
В астрале
Эксперт С++
7994 / 4753 / 321
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
26.09.2010, 03:56  [ТС] #5
alex_x_x, Да) Так и было написано. А тут забыл(
auto_ptr конечно бяка, но сказали, если использовать указатели использовать именно его. У нас ребята и от этого офигевают чуть более чем полностью. Препод буст нам решил пока не давать.
ЗЫ: объявить виртуальным в каком смысле? Сам класс? Или виртуальное наследование?

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

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

Добавлено через 1 минуту
наверное я не уловил гениальность твоей идеи
1
ForEveR
В астрале
Эксперт С++
7994 / 4753 / 321
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
26.09.2010, 04:15  [ТС] #9
niXman, Не моей. Препод попросил так сделать.

Вообщем...

У нас есть класс. Допустим тот же Matr. Шаблонный. В нем есть ввод/вывод в поток (консольный). Попросили сделать так, чтобы от Matr был производный шаблонный класс, в котором и реализуются ввод/вывод на консоль. Это реально? Если нет, то по какой причине, если да, то каким образом. Или не пытаться реализовать эту идею вцелом?
0
alexzak
84 / 57 / 1
Регистрация: 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
ForEveR
В астрале
Эксперт С++
7994 / 4753 / 321
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
26.09.2010, 04:29  [ТС] #11
alexzak, Красиво.
Первый вариант очень понравился.

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

Это не композиция. Это скорее разделение интерфейса и реализации. Интерфейс здесь - это невиртуальный operator*. А реализация - это метод mult_op. (В данном случае он невиртуальный из-за простоты задачи. А мог бы быть, будь задача посложнее.)
1
ForEveR
В астрале
Эксперт С++
7994 / 4753 / 321
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
26.09.2010, 04:57  [ТС] #13
alexzak, Относительно понял. А возможно это сделать не прибегая к паттернам? Виртуальными функциями или же какими-нибудь танцами с бубном? Просто интересно
0
alexzak
84 / 57 / 1
Регистрация: 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
ForEveR
В астрале
Эксперт С++
7994 / 4753 / 321
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
26.09.2010, 05:17  [ТС] #15
alexzak, Если Matr будет конкретный - я не особо вижу смысла переопределять операторы в производном классе. Перегруженные операторы ведь наследуются, а в данном случае оператор умножения матриц не изменится в любом случае. Ибо это стабильная формула. В чем смысл перегрузки оператора * для ConsoleMatr?
0
26.09.2010, 05:17
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.09.2010, 05:17
Привет! Вот еще темы с ответами:

Шаблонный класс - C++
Я запутался с шаблонами. Не пойму никак как вызвать конструктор с введенным в функции check_int() значением и как дальше вызвать функции...

Шаблонный класс - C++
Создание шаблона класса с 1 параметром типа ( шаблонный класс ) По типу : Template&lt;Typename T&gt; Class... #include &lt;iostream&gt; ...

Шаблонный класс - C++
#include &lt;iostream&gt; using namespace std; template &lt;class T&gt; class Vector{ private: int size, capacity; T* data; public: ...

Шаблонный класс - C++
Как его реализовать??? Смысл я понимаю, но вот как записать...не знаю:cry:


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

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

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