Russian Qt Forum

Программирование => С/C++ => Тема начата: Даниил от Апрель 02, 2012, 10:56



Название: Реализация интерфейса[РЕШЕНО]
Отправлено: Даниил от Апрель 02, 2012, 10:56
Приветствую. Возник вопрос, незнаю где найти ответ - как сделать правильно, подскажите?
Имеется интерфейс:
Код
C++ (Qt)
class Number
{
   /* ... */
public:
   virtual Number& operator +(Number& n) = 0;
   /* ...  */
}
 
class PNumber : public Number
{
  /* ... */
private:
   int acc;
public:
   PNumber& operator +(Number& n);
  /* ... */
}
 

Нужно написать реализацию метода для класса PNumber. Затык случился в момент осознания, что мы передаем в метод тип, которые не знает, о существовании PNumber::acc и соотвественно сложение там выполнить нельзя.
Понимаю, что пример христоматийный, но не могу сам додумать и найти не могу в книжках. Подскажите, где искать?


Название: Re: Реализация интерфейса
Отправлено: Пантер от Апрель 02, 2012, 11:18
Закастать?


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 02, 2012, 11:20
Закастать?
А это правильно? Или есть стандартное решение из учебника?
Мне тоже такое в голову лезет, но пока я упорно отбиваюсь от такой идеи.


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 02, 2012, 12:09
Чтобы Вас не грызла совесть - в книжке такого точно нет. Делать операторы виртуальными нет смысла, т.к. все равно так или иначе придется каститься, причем весьма неудобно. Напр Вы написали

Код
C++ (Qt)
   virtual Number& Number::operator +(Number& n) = 0;
   ...
   PNumber& PNumber::operator +(Number& n);
 
Второй даже не будет виртуальным - ведь тип возвращаемого значения разный. Придется городить такую ахинею
Код
C++ (Qt)
Number& PNumber::operator +(Number& n)
{
PNumber * n2 = dynamic_cast <PNumber *> (n);
if (!n2) assert(0);
// складываем
return *this;
}
 

"Правильный" тот оператор который повторяет привычную логику операции без всяких классов. Разве + меняет операнды? Нет (для этого есть +=). Разве он возвращает по ссылке? Нет, по значению. Зачем же Вы пишете оператор + который не облегчает а наоборот?  
Код
C++ (Qt)
// обычная операция
 int a, b c;
 с = a + b;
 
// теперь все то же но с классами
friend PNumber operator + ( const PNumber & pn1, const PNumber & pn2 );
 
 PNumber a, b c;
 с = a + b;
 
Хотя вероятно все это я пишу напрасно - с полгода назад Вы задавали примерно такой же вопрос  :'(


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 02, 2012, 12:15
Хотя вероятно все это я пишу напрасно - с полгода назад Вы задавали примерно такой же вопрос  :'(
Курсовики похожие :) Только тогда была просто реализация. А теперь нужно написать интерфейс - базовый класс, от него породить 3 класса. Суть:
Код
C++ (Qt)
Nump *n = new PNumb();
Nump *n1 = new PNumb();
n = n + n1;
 
Чтобы используя 1 интерфейс можно было манипулировать разными типами.
P.S. Я помню вашу помощь, и ценю ваше внимание.


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 02, 2012, 13:15
Ладно, разжалобили  :)  Сделайте так
Код
C++ (Qt)
// базовый класс
class Number {
Number & operator += ( const Number & n1 )  // сам оператор не виртуальный
{
   return DoVirtalInc(n1);  // но вызывает виртуальный метод
}
 
virtual Number & DoVirtalInc( const Number & n1 ) = 0;
};
 
// порожденный класс
class PNumber {
PNumber & operator += ( const PNumber & n1 )  // обычный не виртуальный оператор
{
   acc += n1.acc;  // складываем
   return *this;
}
 
virtual Number & DoVirtalInc( const Number & n1 )
{
  PNumber * pn1 = dynamic_cast <PNumber *> (&n1);
  if (pn1) *this += *pn1;
  return *this;
}
};
 
В принципе ничего особо не выигрываем - и так и так приводиться надо. Но операторы лучше оставить "обычными", другие очень быстро "вынесут моск"


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 02, 2012, 13:52
Я сдаюсь. Посмотрите задание. Надеюсь меня не спалят >_<


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 02, 2012, 15:59
Обычно операторы сложения, вычитания, умножения и деления делают в виде дружественных функций класса, а не его членами и в этом есть зерно здравого смысла)

Цитировать
Код
C++ (Qt)
Nump *n = new PNumb();
Nump *n1 = new PNumb();
n = n + n1;
 


Это плохая идея. Во-первых n и n1 - это указатели. Формально вы конечно можете их сложить и компилятор даже ничего не скажет) Но в результате получите бред)

Поэтому в любом случае придётся писать делать каст.
Не вижу смысла в базовом (чисто абстрактном) классе объявлять эти операторы, да ещё и виртуальными..   


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 02, 2012, 16:11
Ну да, я там погорячился с указателями - просто хотел передать смысл. А делать операторы сложения, вычитания ... в виде дружественных функций - это нарушение ООП. Так что, ата-та-та.


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 02, 2012, 16:33
Ну да, я там погорячился с указателями - просто хотел передать смысл. А делать операторы сложения, вычитания ... в виде дружественных функций - это нарушение ООП. Так что, ата-та-та.
Где это там нарушение ООП?)

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

   
 


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 02, 2012, 16:43
Нарушение инкапсуляции идет. Я уже получил звездюлей за такую реализацию. О внутренних деталях класса должен знать только класс. А сторонние функции/классы должны иметь доступ только к методам.
Может быть в вашем случае большая гибкость получается - не спорю. Но типа как - не клёва ^_^  ;D  ;D  ;D


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 02, 2012, 16:46
идея. Во-первых n и n1 - это указатели. Формально вы конечно можете их сложить и компилятор даже ничего не скажет)
Очень даже скажет (указатель + целое = новый указатель, но не указатель + указатель)

А делать операторы сложения, вычитания ... в виде дружественных функций - это нарушение ООП. Так что, ата-та-та.
Лучше совершенствоваться в языке чем в демагогии.

Я сдаюсь. Посмотрите задание. Надеюсь меня не спалят >_<
С точки зрения ++ такая реализация (как в Вашей методичке) неосуществима.

Код
C++ (Qt)
class TANumber
{
   ...
   virtual TANumber& operator + (TANumber& B) = 0;
 
Это значит что все классы наследующие TANumber должны иметь свои операторы + описанные точно так же как этот.

Код
C++ (Qt)
class TReal : public TANumber
{
   ...
   virtual TReal&  operator + (TANumber& B);
};
 
Тип возвращаемого значения другой - значит это уже другой (еще один) оператор. Компилятор будет вякать пока Вы не объявите так
Код
C++ (Qt)
class TReal : public TANumber
{
   ...
   virtual TNumber &  operator + (TANumber& B);
};
 
Иначе TReal - абстрактный класс и создавать объекты такого типа нельзя

Я уже получил звездюлей за такую реализацию.
Хмм.. ну вообще-то правильно дали (хоть и не за то что надо)  :)


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 02, 2012, 16:53
В пятницу пойду поговорю с человеком, который оформлял задание и отпишусь о результатах. Ну, максимум в субботу.


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 02, 2012, 17:08
Не слишком полагайтесь на эту методичку. Напр там пишут
Код
C++ (Qt)
virtual bool    operator == (TANumber& B);
 
А правильно так
Код
C++ (Qt)
virtual bool operator == (const TANumber& B) const;
 
Конечно не надо конфликтовать и пытаться чего-то доказывать. Просто молча пишите правильно, за это не убьют


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 02, 2012, 17:09
Нарушение инкапсуляции идет. Я уже получил звездюлей за такую реализацию. О внутренних деталях класса должен знать только класс. А сторонние функции/классы должны иметь доступ только к методам.
Может быть в вашем случае большая гибкость получается - не спорю. Но типа как - не клёва ^_^  ;D  ;D  ;D

Интересно, почему же тогда во всех серьёзных мат. библиотеках эти операторы (+ - *) делаются в виде дружественных функций?
Вот небольшой пример:
Код
C++ (Qt)
class Number
{
public:
   Number() : _x(0) {}
   Number(int x) : _x(x) {}
   Number &operator+(const Number &x) {
       _x += x._x;
       return *this;
   }
   friend std::ostream& operator<<(std::ostream&, const Number&);
   //friend const Number operator+(const Number&, const Number&);
private:
   int _x;
};
 
std::ostream& operator<<(std::ostream& out, const Number& x) {
   out << x._x;
   return out;
}
 
/*
const Number operator+(const Number&x1, const Number &x2) {
   return Number(x1._x + x2._x);
}
*/

 
Number n1 = 1;
Number n2 = 2;
 
Number n3 = n1+(1+n2);
 
cout << n3 << endl;
 
 
Попробуйте скомпилируйте это, когда оператор сложения - член класса.
А если не получится, закомментируйте его и раскомментируйте вариант, где этот оператор в виде дружественной функции.  


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 02, 2012, 17:13
Нарушение инкапсуляции идет. Я уже получил звездюлей за такую реализацию. О внутренних деталях класса должен знать только класс. А сторонние функции/классы должны иметь доступ только к методам.
Может быть в вашем случае большая гибкость получается - не спорю. Но типа как - не клёва ^_^  ;D  ;D  ;D

Интересно, почему же тогда во всех серьёзных мат. библиотеках эти операторы (+ - *) делаются в виде дружественных функций?
Вот небольшой пример:
Код
C++ (Qt)
class Number
{
public:
   Number() : _x(0) {}
   Number(int x) : _x(x) {}
   Number &operator+(const Number &x) {
       _x += x._x;
       return *this;
   }
   friend std::ostream& operator<<(std::ostream&, const Number&);
   //friend const Number operator+(const Number&, const Number&);
private:
   int _x;
};
 
std::ostream& operator<<(std::ostream& out, const Number& x) {
   out << x._x;
   return out;
}
 
/*
const Number operator+(const Number&x1, const Number &x2) {
   return Number(x1._x + x2._x);
}
*/

 
Number n1 = 1;
Number n2 = 2;
 
Number n3 = n1+(1+n2);
 
cout << n3 << endl;
 
 
Попробуйте скомпилируйте это, когда оператор сложения - член класса.
А если не получится, закомментируйте его и раскомментируйте вариант, где этот оператор в виде дружественной функции.  

Операторы вывода "<<" или ввода ">>" всегда перегружают как дружественные, это исключение. Во всех учебниках написано.
P.S. И да, что закоментирован, что не закоментирован дружественный оператор  ;D Это читерство


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 02, 2012, 17:18
Цитировать
Операторы вывода "<<" или ввода ">>" всегда перегружают как дружественные, это исключение. Во всех учебниках написано.
Я говорю о операторе сложения.
Тот пример, что приведён выше не будет работать, если оператор+ является членом класса.

У подхода, когда подобные операторы выносятся в виде функций есть ещё одно преимущество..    

Цитировать
P.S. И да, что закоментирован, что не закоментирован дружественный оператор   Это читерство
Это вам для наглядности))


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 02, 2012, 17:24
В вашем примере - может и не будет. А вот в этом:
Код
C++ (Qt)
class TPNumber
{
  /* .......... */
  TPNumber operator +(const TPNumber &p1);
  /* .......... */
}
 
TPNumber TPNumber::operator +(const TPNumber &p1)
{
       return TPNumber(this->number + p1.number, this->sistemaSchisleniya, this->tochnost);
}
 
Все работает и сдано с оценкой - отлично. Кстати отчасти этой оценке я благодарен данному форуму :)


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 02, 2012, 17:36
Цитировать
Все работает и сдано с оценкой - отлично. Кстати отчасти этой оценке я благодарен данному форуму
Вы меня не понимать)

Хорошо, объясню на вашем примере.
Пусть у вас есть два класса чисел Number и NumberF.
Так вот, если вы пойдёте по пути когда оператор+ у них будет членом, то выражения вида:
Код
C++ (Qt)
Number x = 1;
NumberF y = 3.14;
 
NumberF sum = x + y; // Внимание сюда!
 
 
вам будет проблематично реализовать. Придётся лезть  в эти классы и добавлять в них доп. операторы+
Тем самым создавая связи между этими классами, от которых в ООП так пытаются избавиться)


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 02, 2012, 17:39
Цитировать
Все работает и сдано с оценкой - отлично. Кстати отчасти этой оценке я благодарен данному форуму
Вы меня не понимать)

Хорошо, объясню на вашем примере.
Пусть у вас есть два класса чисел Number и NumberF.
Так вот, если вы пойдёте по пути когда оператор+ у них будет членом, то выражения вида:
Код
C++ (Qt)
Number x = 1;
NumberF y = 3.14;
 
NumberF sum = x + y; // Внимание сюда!
 
 
вам будет проблематично реализовать. Придётся лезть  в эти классы и добавлять в них доп. операторы+
Тем самым создавая связи между этими классами, от которых в ООП так пытаются избавиться)

Собственно я никогда и не хотел складывать разнотипные объекты*. Типы всегда одинаковые, это контролируется программно. Просто я хотел, чтобы они ссылки на них хранились в указателях на их базовый класс, чтобы в процессе работы программы, я бы мог сменить тип обоих указателей и выполнить сложение двух других типов.


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 02, 2012, 17:54
Цитировать
Просто я хотел, чтобы они ссылки на них хранились в указателях на их базовый класс, чтобы в процессе работы программы, я бы мог сменить тип обоих указателей и выполнить сложение двух других типов.
Как вы себе это представляете?
Так:
Код
C++ (Qt)
Number *n1 = new NumberF(3.14);
Number *n2 = new NumberF(2.71);
 
*n2 = *n2 + *n1;
 
Так не получится. Number - чисто абстрактный класс и разыменовать n1 и n2 не получится.
Какой смысл объявлять в интерфейсном классе Number эти операторы?
Интересно, кто у вас там методички пишет?)    


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 02, 2012, 18:01
Код
C++ (Qt)
TPNumber TPNumber::operator +(const TPNumber &p1)
{
       return TPNumber(this->number + p1.number, this->sistemaSchisleniya, this->tochnost);
}
 
Все работает и сдано с оценкой - отлично.
Вполне заслуженно, но с минусом: этот оператор должен быть константным
Код
C++ (Qt)
TPNumber TPNumber::operator +(const TPNumber &p1) const
 
Вообще для оператора + "что в лоб что по лбу" - ведь он использует сам класс и все. Поэтому оператор-член и friend равноценны

вам будет проблематично реализовать. Придётся лезть  в эти классы и добавлять в них доп. операторы+
Тем самым создавая связи между этими классами, от которых в ООП так пытаются избавиться)
m_ax говорит умные вещи (иногда), стоит прислушаться. Почему те же операторы слива в поток обычно friend? Потому что если бы это были операторы-члены - нам пришлось бы писать так

Код
C++ (Qt)
#include <fstream>  
 
class PNumber {
...
};
 
Потом, по каким-то причинам мы решили перевести I/O напр на Qt. Придется писать  #include <QFile>, удалять #include <fstream>  и кромсать хедер в котором PNumber. Вот они - те "плохие" связи. Поэтому лучше сделать PNumber независимым
 
Так не получится. Number - чисто абстрактный класс и разыменовать n1 и n2 не получится.
Какой смысл объявлять в интерфейсном классе Number эти операторы?
Интересно, кто у вас там методички пишет?)   
Чего ж это я не могу разыменовать указатель на абстрактный класс? Ну получу ссылку на абстрактный класс, все нормуль.


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 02, 2012, 18:59
Мы отошли немного от темы. Вопрос в принципе теперь в лоб, т.к. мы уже разобрали множество вариантов: как лучше организовать? через касты или другие методы искать?


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 02, 2012, 19:21
Мы отошли немного от темы. Вопрос в принципе теперь в лоб, т.к. мы уже разобрали множество вариантов: как лучше организовать? через касты или другие методы искать?
Ну выбора-то у Вас нет, кастить придется. Мое мнение что базовый класс должен иметь операторы которые вызывают виртуальные ф-ции которые уже вызывают "родные" операторы. См пример реализации выше. Не хотите "показаться слишком умным" - ну это можно понять, нормально. Тогда тупо передираете текст методички, только типы возвращаемых значений везде ставите TNumber (по-другому не получится). Ну и каститесь внутри каждого оператора.


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 02, 2012, 20:42
Вобщем, я пока так решил сделать, по вашим советам через касты:
Код
C++ (Qt)
class Number
{
  /* ... ... ... */
public:
   virtual Number& operator =(Number &n) = 0;
   virtual Number& operator +(Number &n) = 0;
   /* ... ... ... */
};
 
class PNumber : public Number
{
  /* ... ... ... */
   Number& operator =(Number &p1);
   Number& operator +(Number &p1);
  /* ... ... ... */
};
 
Number& PNumber::operator +(PNumber &p1)
{
   PNumber *pn;
   Number *n = &p1;
   pn = dynamic_cast<PNumber *>(n);
   pn->number += this->number;
   return *pn;
}
 
Возможно слишком криво, но вполне отвечает задумке ;)


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 02, 2012, 20:57
Цитировать
Код
C++ (Qt)
Number& PNumber::operator +(PNumber &p1)
{
   PNumber *pn;
   Number *n = &p1;
   pn = dynamic_cast<PNumber *>(n);
   pn->number += this->number;
   return *pn;
}
 
Что-то страшное вы здесь написали)
 


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 02, 2012, 21:11
Напишите проще, если сможете  :P


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 02, 2012, 23:23
Напишите проще, если сможете  :P
Нужно стремиться делать не как проще, а как правильнее)

Я бы сделал примерно так (упрощённый вариант)
Код
C++ (Qt)
enum NumberType {TNumberInt, TNumberF};
 
class Sum;
 
class Number
{
public:
   virtual ~Number() {}
   virtual NumberType type() const = 0;
   virtual Number& operator=(const Number&) = 0;
   virtual Number& operator=(const Sum&) = 0;
};
 
class Sum
{
public:
   Sum(const Number& x1, const Number& x2) : _x1(x1), _x2(x2) {}
   const Number& x1() const { return _x1; }
   const Number& x2() const { return _x2; }
   NumberType type() const { return _x1.type(); }
private:
   const Number& _x1;
   const Number& _x2;
};
 
 
class NumberInt : public Number
{
public:
   NumberInt() : _x(0) {}
   NumberInt(int x) : _x(x) {}
 
   virtual NumberType type() const { return TNumberInt; }
 
   virtual Number& operator=(const Number&x) {
       if (x.type() != TNumberInt)
           throw "error!";
 
       const NumberInt& num = static_cast<const NumberInt&>(x);
       _x = num._x;
       return *this;
   }
 
   virtual Number& operator=(const Sum& s) {
       if (s.type() != TNumberInt)
           throw "error!";
 
       const NumberInt& i1 = static_cast<const NumberInt&>(s.x1());
       const NumberInt& i2 = static_cast<const NumberInt&>(s.x2());
       _x = i1._x + i2._x;
       return *this;
   }
 
   friend const NumberInt operator+(const NumberInt&, const NumberInt&);
   friend std::ostream& operator<<(std::ostream&, const NumberInt&);
private:
   int _x;
};
 
 
std::ostream& operator<<(std::ostream& out, const NumberInt& x) {
   out << x._x;
   return out;
}
 
const Sum operator+(const Number& x1, const Number& x2) {
   return Sum(x1, x2);
}
 
const NumberInt operator+(const NumberInt& x1, const NumberInt& x2) {
   return NumberInt(x1._x + x2._x);
}
 
 
int main()
{
   Number *n1 = new NumberInt(1);
   Number *n2 = new NumberInt(2);
 
   *n1 = *n2 + *n2;
 
   cout << static_cast<const NumberInt&>(*n1);
 
   return 0;
}
 
Этот приём используется в boost ublas и в blitz, но совсем для другой цели - чтоб избавится от создания временных объектов (матриц, векторов) при операциях сложения, вычитания, умножения и пр. с ними.   


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 03, 2012, 06:13
Что-то страшное вы здесь написали)
Это я то страшное написал?!
Чем ваш вариант правильнее моего? Тем, что уже так кто-то делал в популярной библиотеке?

P.S. Хорошо, варианты реализации могут быть самыми разными. Я подстраивал свое решение под конкретную проблему, чтобы после иметь возможность добавлять другие классы не переписывая управляющих конструкций. Если интересно - позже могу выложить весь материал по данной проблеме.


Название: Re: Реализация интерфейса
Отправлено: Tonal от Апрель 03, 2012, 08:53
И никто не вспомнил о методе двойной диспетчеризации. :)
Правда, в данном случае для стандартных сигнатур операторов красиво не выйдет, поэтому проще показывать на обычных функциях.
Это делается примерно так:
Код
C++ (Qt)
struct Number {
 virtual const Number* add(const Number* other) const = 0;
};
 
// Собственно операции с "числами"
Number* add(const Number* x, const Number* y) {
 return x->add(y);
}
...
// Реализация двойной деспеччиризации
struct Int;
struct Rational;
struct Real;
 
struct Int : Number {
 virtual const Number* add(const Number* other) const {
   return other->addInt(this);
 }
 
 const Int* addInt(const Int* other) const {
   return new Int(val + other->val);
 }
 const Rational* addRational(const Rational* other) const {
   return other->addInt(this);
 }
 const Real* addReal(const Real* other) const {
   return other->addInt(this);
 }
 int get_val() const {
   return val;
 }
 private:
   int val;
};
 
struct Rational : Number {
 virtual const Number* add(const Number* other) const {
   return other->addRational(this);
 }
 
 const Rational* addInt(const Int* o) const {
   return new Rational(nom + denom * o->get_val(), denom);
 }
 const Rational* addRational(const Rational* o) const {
   return Rational(nom * o->denom + o->nom + denom, denom * o->denom);
 }
 const Real* addReal(const Real* other) const {
   return other->addRational(this);
 }
 private:
   int nom, denom;
};
...
 
Как можно убедится нигде нет нужды в явном приведении типов. :)
Да и по эффективноси, данный метод добавляет всего 1 косвенный вызов, вместо переборов перечислений или сравнений строк. :)

Двойная диспетчеризация - это частный случай реализации мультиметодов в С++.
Работает с полиморфизмом по 2м параметрам вместо 1 как в обычной виртуальности.
Можно расширить и на большее количество аргументов, если не боятся много писать. :)

Короче, читайте Страуструпа - он рулит! :)


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 03, 2012, 10:37
С удивлением обнаружил что, оказывается, в методичке все правильно написано - а я был неправ!
Код
C++ (Qt)
struct CTest1 {
CTest1( void ) : mA(1) {}
virtual CTest1 & operator + ( CTest1 & src ) = 0;
virtual CTest1 & Func( void ) = 0;
 
// data
int mA;
};
 
struct CTest2 : public CTest1 {
virtual CTest2 & operator + ( CTest1 & src )
{
mA += src.mA;
return *this;
}
 
virtual CTest2 & Func( void )
{
++mA;
return *this;
}
};
 
int main(int argc, char **argv)
{
CTest2 a, b;
b = a.Func();
a = a + b;
return 0;
}
 
То есть виртуальные методы могут возвращать разные типы ссылок. Мда :)


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 03, 2012, 10:51
Как можно убедится нигде нет нужды в явном приведении типов. :)
Да и по эффективноси, данный метод добавляет всего 1 косвенный вызов, вместо переборов перечислений или сравнений строк. :)
Так ведь расплата за это "каждый класс знает каждого". И в данном случае он не очень к месту, т.к. не планируются смешанные операции с разнородными классами. А приемчик красивый, кстати он часто помогает "раскрутить" template 


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 03, 2012, 11:16
Возможно слишком криво, но вполне отвечает задумке ;)
Да все нормально, только типы возврата верните взад (это я насвистел) и не забывайте после dynamic_cast проверяться на NULL

Дело вот в чем
Код
C++ (Qt)
virtual TReal &  TReal::operator + (TNumber& B);   // ну "очень странный" оператор +
virtual TReal TReal::operator + (const TNumber& B) const;  // "нормальный" оператор +
 
Первое впечатление что такой кривой оператор написал безграмотный человек :) Но это не так. Дело в том что "нормальный" оператор мы никак не сможем уложить в виртуальный механизм т.к. он возвращает по значению. TReal & (ссылка) может быть чем-то иным, но "просто TReal" нет - это только объект типа TReal". Др словами чтобы работали виртуалы - приходится изуродовать нормальную логику операторов.

Если уж идти "до упора", то тогда так
Код
C++ (Qt)
virtual TReal & TReal::operator + (const TNumber& B) const;  
 
Это сохраняет нормальную логику +, но на что тогда указывает возвращаемая ссылка? Можно напр хранить в кольцевом буфере. Ладно, это уже "как правильно", разумеется за рамками лабы, не парьтесь


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 03, 2012, 11:58
Другими словами логика правильная, нужно просто проверку делать на bad_cast? В обработку исключения не проще засунуть?


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 03, 2012, 12:09
Другими словами логика правильная, нужно просто проверку делать на bad_cast? В обработку исключения не проще засунуть?
dynamic_cast не генерирует исключений а просто возвращает 0 если приведение невозможно. Проверяйте и вываливайтесь по нулю
Код
C++ (Qt)
pn = dynamic_cast<PNumber *>(n);
if (!pn) assert(0);    // добавьте эту строчку
 


Название: Re: Реализация интерфейса
Отправлено: V1KT0P от Апрель 03, 2012, 12:12
Другими словами логика правильная, нужно просто проверку делать на bad_cast? В обработку исключения не проще засунуть?
dynamic_cast не генерирует исключений а просто возвращает 0 если приведение невозможно. Проверяйте и вываливайтесь по нулю
Код
C++ (Qt)
pn = dynamic_cast<PNumber *>(n);
if (!pn) assert(0);
 
Может все-таки лучше так:
Код
C++ (Qt)
assert(pn != 0);
Проще воспринимается.


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 03, 2012, 12:24
dynamic_cast не генерирует исключений а просто возвращает 0 если приведение невозможно. Проверяйте и вываливайтесь по нулю
Не понял, а это тогда что? http://www.cplusplus.com/reference/std/typeinfo/bad_cast/ (http://www.cplusplus.com/reference/std/typeinfo/bad_cast/)


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 03, 2012, 12:37
Не понял, а это тогда что? http://www.cplusplus.com/reference/std/typeinfo/bad_cast/ (http://www.cplusplus.com/reference/std/typeinfo/bad_cast/)
Так это если приводите ссылку, а у Вас указатель. Ну в данном случае можно и ссылку приводить - дело вкуса

Может все-таки лучше так:
Код
C++ (Qt)
assert(pn != 0);
Проще воспринимается.
Согласен  :)


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 03, 2012, 14:17
Цитировать
Код
C++ (Qt)
virtual TReal &  TReal::operator + (TNumber& B);   // ну "очень странный" оператор +
virtual TReal TReal::operator + (const TNumber& B) const;  // "нормальный" оператор +
 

Первое впечатление что такой кривой оператор написал безграмотный человек  Но это не так. Дело в том что "нормальный" оператор мы никак не сможем уложить в виртуальный механизм т.к. он возвращает по значению. TReal & (ссылка) может быть чем-то иным, но "просто TReal" нет - это только объект типа TReal". Др словами чтобы работали виртуалы - приходится изуродовать нормальную логику операторов.
Я об этом и говорил. И ещё у меня подозрение (не проверял), что здесь:
Код
C++ (Qt)
virtual TReal &  TReal::operator + (TNumber& B);   // ну "очень странный" оператор +
 
Изменяется и сам объект B, что кажется немного безумным)
Вы складываете два числа и одно из них (B) также меняется в результате сложения. Или оно не меняется? Тогда почему передаётся по ссылке, а не по константной ссылке?

Вобщем я считаю, что подобный выкрутас в контексте данного класса чисел, выглядит бредовым.. Имхо, можно найти решение и по изящней. 


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 03, 2012, 14:51
Изменяется и сам объект B, что кажется немного безумным)
Вы складываете два числа и одно из них (B) также меняется в результате сложения. Или оно не меняется? Тогда почему передаётся по ссылке, а не по константной ссылке?
Там и первый операнд (сам класс) меняется  - что, мягко говоря, нетипично для оператора +  :)
И да, полное отсутствие const конечно минус авторам методички - потом очень трудно будет переучиваться, начнутся отмазки типа "та зачем, ведь и так работает"


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 03, 2012, 15:15
Цитировать
И да, полное отсутствие const конечно минус авторам методички - потом очень трудно будет переучиваться, начнутся отмазки типа "та зачем, ведь и так работает"
Дело даже не в том, что const, не const.. Просто им дают изначально задания из разряда - как делать не надо (в смысле как проектировать не надо), но при этом в полной уверенности что так и должно быть с точки зрения архитектуры.
А потом, при использовании таких чисел неожиданно выясняется (это в лучшем случае) что все аксиомы математики противоречат таким числам) 


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 03, 2012, 16:03
Дело даже не в том, что const, не const.. Просто им дают изначально задания из разряда - как делать не надо (в смысле как проектировать не надо), но при этом в полной уверенности что так и должно быть с точки зрения архитектуры.
Ну хорошо, вот допустим Вы (или я) преподаватель. И что? Это одного мы сможем как-то поднатаскать (в меру наших скромных сил) - и то надо возиться с ним ого-го сколько. А что делать с группой из 20 чел (а из них любят программирование дай бог 2)? Вдаваться в нюансы архитектуры явно бесполезно. Дать одно "творческое задание" на всех? Так они перепишут друг у друга. А настаивая на "глубоком изучении" мы быстро заработаем славу препода который "выделывается" и.т.п. :) По-любому приходится как-то упрощать, обрезать тонкости, иначе процесс образования невозможен.


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 03, 2012, 20:13
Изменяется и сам объект B, что кажется немного безумным)
Как я понимаю, речь идет об отсутствии в описании метода спецификатора "const". Мне сначала показалось это ошибкой, но позже у меня возникли проблемы с кастованием константных данных. Если приведете работающий пример, буду признателен.


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 03, 2012, 20:44
Изменяется и сам объект B, что кажется немного безумным)
Как я понимаю, речь идет об отсутствии в описании метода спецификатора "const". Мне сначала показалось это ошибкой, но позже у меня возникли проблемы с кастованием константных данных. Если приведете работающий пример, буду признателен.
Речь идёт о том, что у вас при сложении двух чисел A и B меняются  эти два числа:
C = A + B;
После такого сложения A и B изменят свои значения. Это нормально?
Как вообще такими числами пользоваться?
Суперматематика отдыхает))

Я вам уже приводил пример, но вам он не понравился(  Посмотрите на пример, который привёл Tonal
 


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 04, 2012, 06:25
Я вам уже приводил пример, но вам он не понравился(  Посмотрите на пример, который привёл Tonal
Ни вы, никто другой не приводил пример в котором в метод передается значение, а после приводится к другому типу.


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 04, 2012, 09:31
Я вам уже приводил пример, но вам он не понравился(  Посмотрите на пример, который привёл Tonal
Ни вы, никто другой не приводил пример в котором в метод передается значение, а после приводится к другому типу.
И правильно сделали, что не стали приводить заведомо костыльные решения)

Смотрите: Кода в классе (абстрактном) пишут подобные объявления оператора+
Код
C++ (Qt)
class TANumber
{
public:
   virtual ~Number() {}
   virtual TANumber& operator+(TANumber&) = 0;
//...
};
 
Возникает подозрение, что у автора либо проблемы с математикой, либо непонимание в прегрузки операторов. Либо и то и другое)
Причём, класс реализует число и, соответственно, все операции с этими числами не должны противоречить математике.
Но вам в вашей методичке явно указывают как вы должны делать. Так вот так делать как раз не надо)
Это костыльный безграмотный вариант.
Или ещё не очевидно почему это так?

   


Название: Re: Реализация интерфейса
Отправлено: Tonal от Апрель 04, 2012, 09:39
Как можно убедится нигде нет нужды в явном приведении типов. :)
Да и по эффективноси, данный метод добавляет всего 1 косвенный вызов, вместо переборов перечислений или сравнений строк. :)
Так ведь расплата за это "каждый класс знает каждого".
Ну а когда ты явно кастишь dynamic_cast-ом ты типы не знаешь? :)
Хотя это действительно ограничение данного метода - при добавлении нового класса нужно добавлять функции его обработки во все классы.
Иногда это можно ослабить с помощью наследования...

И в данном случае он не очень к месту, т.к. не планируются смешанные операции с разнородными классами.
Перечитал стартовый топик.
ИМХО, задание как раз было на использование dynamic_cast либо сравнение type_info. :)

Решения с перечислениями вполне аналогичны двойной диспетчеризации - и там и там нужно предварительно объявить состав производных классов.
Причём решение с перечисленим хуже - т. к. не практически не проверяется компилятором.

Да, нет нужды в смешанных операциях, то с добавлением нового класса меняется сигнатура только базового объекта:
Код
C
struct SomeNumber;
 
struct BaseNumber {
 virtual const BaseNumber& operator + (const BaseNumber&) const = 0;
 protected:
   virtual const BaseNumber& add_to(const BaseNumber&) const {throw std::bad_cast();}
   virtual const SomeNumber& add_to(const SomeNumber&) const = 0;
};
struct SomeNumber : BaseNumber {
 virtual const SomeNumber& operator + (const BaseNumber& other) const {
   return other.add_to(*this);
 }
 protected:
   virtual const SomeNumber& add_to(const SomeNumber&) const;
};
 
А приемчик красивый, кстати он часто помогает "раскрутить" template
В шаблонах как раз полиморфизм по всем параметрам. Так что там в этом приёмчике смысла большого нет. :)

П. С. Да, в С++ разрешеатся в переопределённом виртуальном методе возвращать указатель/ссылку производного типа, а не того, который был объявлен в предке.
Так что оператор в примере выше действительно виртуальный.


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 04, 2012, 10:35
Я вам уже приводил пример, но вам он не понравился(  Посмотрите на пример, который привёл Tonal
Ни вы, никто другой не приводил пример в котором в метод передается значение, а после приводится к другому типу.
И правильно сделали, что не стали приводить заведомо костыльные решения)

Смотрите: Кода в классе (абстрактном) пишут подобные объявления оператора+
Код
C++ (Qt)
class TANumber
{
public:
   virtual ~Number() {}
   virtual TANumber& operator+(TANumber&) = 0;
//...
};
 
Возникает подозрение, что у автора либо проблемы с математикой, либо непонимание в прегрузки операторов. Либо и то и другое)
Причём, класс реализует число и, соответственно, все операции с этими числами не должны противоречить математике.
Но вам в вашей методичке явно указывают как вы должны делать. Так вот так делать как раз не надо)
Это костыльный безграмотный вариант.
Или ещё не очевидно почему это так?

   
Я все понял, а вы очевидно не читаете мои сообщения, а рассуждаете наедине с самим собой. Я не спрашиваю вас как решить мою задачу. Это я уже понял сам. Я спросил вполне конкретный вопрос.
Цитировать

... у меня возникли проблемы с кастованием константных данных. Если приведете работающий пример, буду признателен.


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 04, 2012, 10:51
Цитировать
Я все понял, а вы очевидно не читаете мои сообщения, а рассуждаете наедине с самим собой. Я не спрашиваю вас как решить мою задачу. Это я уже понял сам. Я спросил вполне конкретный вопрос.

Цитировать
... у меня возникли проблемы с кастованием константных данных. Если приведете работающий пример, буду признателен.
А вы мои читаете?
В вашем варианте (тот что в методичке) сделать каст по константной ссылке не получится. Угадайте почему)
И как следствие при операциях сложения, вычитания и пр. у вас автоматически будут меняться сами числа, участвующие в данных операциях.
Осмыслите то, что вы делаете, а не слепо следуйте сомнительным указаниям)   


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 04, 2012, 10:56
Есть такие ситуации в нашей жизни, когда нужно сделать так, как говорят другие люди, т.к. за ваш труд платят они и вам лучше плюнуть на свою гордость ...
Но, что-то мы немного отвлеклись. Всем спасибо за участие в обсуждение, вы все мне помогли осмыслить новые приемы в программирование на C++.
Спасибо, m_ax.
Спасибо, Tonal.
Спасибо, Igors.
Спасибо, V1KT0P.
Спасибо, Пантер (он кстати первым выдвинул корректную идею  :P).


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 04, 2012, 11:03
Цитировать
Есть такие ситуации в нашей жизни, когда нужно сделать так, как говорят другие люди, т.к. за ваш труд платят они и вам лучше плюнуть на свою гордость ...
Да, есть такие ситуации, кто же спорит..
Только вот сейчас это вы платите за такие решения и за такое образование.. 


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 04, 2012, 12:35
struct SomeNumber : BaseNumber {
  virtual const SomeNumber& operator + (const BaseNumber& other) const
 }
Какой Вы умный :)  А на что же ссылается возвращаемое SomeNumber ?

Даниил, не обращайте внимания, Ваша лаба (давно) ни при чем, это мы о том "как правильно"  :)


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 04, 2012, 17:02
Вобщем, я пока так решил сделать, по вашим советам через касты:
Код
C++ (Qt)
class Number
{
   /* ... ... ... */
public:
   virtual Number& operator =(Number &n) = 0;
   virtual Number& operator +(Number &n) = 0;
   /* ... ... ... */
};
 
class PNumber : public Number
{
   /* ... ... ... */
   Number& operator =(Number &p1);
   Number& operator +(Number &p1);
   /* ... ... ... */
};
 
Number& PNumber::operator +(PNumber &p1)
{
   PNumber *pn;
   Number *n = &p1;
   pn = dynamic_cast<PNumber *>(n);
   pn->number += this->number;
   return *pn;
}
 
Возможно слишком криво, но вполне отвечает задумке ;)
Что ж вы за люди такие, могли ж конкретно носом ткнуть, что изменяю второй операнд  :'( Только сейчас нашел ...


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 04, 2012, 17:08
Цитировать
Что ж вы за люди такие, могли ж конкретно носом ткнуть, что изменяю второй операнд   Только сейчас нашел ...
Уж какие есть) Хотя я об этом вам уже неоднократно писал. Но вы, видимо, не обращаете на это внимания.. Что ж вы за человек такой))

Уверяю вас, вы ещё много костылей найдёте, если будете придерживаться той схемы, что предложена вам в той методичке..   


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 04, 2012, 17:12
Оригинальный у вас метод помощи, т.е. если к вам подбежит человек, у которого сломана рука, вы отправите его в магазин за книгой? (естественно вы будете точно знать, что книга там про переломы есть)
Я к тому, что можно было написать конкретно: "В вашем варианте, происходит изменения передаваемого по ссылке объекта".
А не отправлять думать над архитектурой программы, ссылаюсь на некоторые возможные проблемы :\

*Сломанной ногой, с рукой сломанной ходить можно ... а тут явный баг будет =]


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 04, 2012, 17:20
Оригинальный у вас метод помощи, т.е. если к вам подбежит человек, у которого сломана рука, вы отправите его в магазин за книгой? (естественно вы будете точно знать, что книга там про переломы есть)
Я к тому, что можно было написать конкретно: "В вашем варианте, происходит изменения передаваемого по ссылке объекта".
А не отправлять думать над архитектурой программы, ссылаюсь на некоторые возможные проблемы :\

Перечитайте, пожалуйста повнимательнее мой пост № 38, № 43 и № 48


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 04, 2012, 17:25
Действительно, нашел. Ну очень осторожный совет. Да, был не прав. Извиняюсь.
Но думаю, в след. раз вам не помешало бы более конкретно выражать ваши мысли.


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 04, 2012, 17:25
Что ж вы за люди такие, могли ж конкретно носом ткнуть, что изменяю второй операнд  :'( Только сейчас нашел ...
Так написано же так
Код
C++ (Qt)
Number& PNumber::operator +(PNumber &p1)
 
p1 константная ссылка? Нет - ну значит этот оператор его будет менять. Забили на const - получайте


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 04, 2012, 17:31
Забили на const - получайте
Не "забили", а не использовали, в виду либо невозможности, либо неопытности.


Название: Re: Реализация интерфейса
Отправлено: Tonal от Апрель 05, 2012, 11:43
struct SomeNumber : BaseNumber {
  virtual const SomeNumber& operator + (const BaseNumber& other) const
 }
Какой Вы умный :)  А на что же ссылается возвращаемое SomeNumber ?
О, точно подмечено! :) Видимо по этому до сих пор и не богатый.
Ссылок в сигнатуре, конечно, быть не должно.
Что, однако, никак не влияет на остальные рассуждения. :)


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 05, 2012, 11:57
struct SomeNumber : BaseNumber {
  virtual const SomeNumber& operator + (const BaseNumber& other) const
 }
Какой Вы умный :)  А на что же ссылается возвращаемое SomeNumber ?
О, точно подмечено! :)
Ссылок в сигнатуре, конечно, быть не должно.
Что, однако, никак не влияет на остальные рассуждения.  :)
Влияет т.к. возвращая по значению мы никак не сделаем оператор (реально) виртуальным.


Название: Re: Реализация интерфейса
Отправлено: Tonal от Апрель 06, 2012, 08:41
Ссылок в сигнатуре, конечно, быть не должно.
Что, однако, никак не влияет на остальные рассуждения.  :)
Влияет т.к. возвращая по значению мы никак не сделаем оператор (реально) виртуальным.
И опять согласен. :)
Причём сам же, в первом своём сообщении это учёл и написал:
Правда, в данном случае для стандартных сигнатур операторов красиво не выйдет, поэтому проще показывать на обычных функциях.
Хотя вариант сохранить сигнатуру таки есть :)
Если к коду, приведённому в первом посте (http://www.prog.org.ru/index.php?topic=21490.msg149030#msg149030) добавить оболочку:
Код:
struct AllNumber {
  const AllNumber operator + (const AllNumber& other) const {
    return AllNumber(val.get()->add(other.val.get()));
  }
  private:
    std::auto_ptr<Number> val;
};
И пользоваться только AllNumber. :)


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 06, 2012, 12:29
Хотя вариант сохранить сигнатуру таки есть :)
...
Код:
struct AllNumber {
  const AllNumber operator + (const AllNumber& other) const {
    return AllNumber(val.get()->add(other.val.get()));
  }
  private:
    std::auto_ptr<Number> val;
};
И пользоваться только AllNumber. :)
Ну "пользоваться только" - это несолидно. А почему не так

Код
C++ (Qt)
struct CFractNumber : public CBaseNumber {
 CFractNumber & operator + (const CBaseNumber & other) const
 {
   assert(dynamoc_cast <const CFactNumber *> &other) != 0);
   CFractNumber & result = mBuf[mBufCount];
   result = *this;
   mBufCount = (mBufCount + 1) % BUF_SIZE;
   return result += other;
 }
 
 private:
   static int mBufCount = 0;
   static CFractNumber mBuf[BUF_SIZE];
 
   enum {
     BUF_SIZE = 256,
   };
};
 


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 06, 2012, 12:36
Самое правильное решение - это отказаться от такого кастыльного пути и вынести уже все операторы+ (-) и подобные бинарные операторы из класса, реализовав их по человечески в виде функций (возможно дружественных).
Тогда все ваши проблемы и потребность в этих костылях сами собой отпадут) 


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 06, 2012, 12:48
Самое правильное решение
Само по себе существование такого решения в мире программирования на C++ абсурдно. Есть субъективные мнения и не более. И даже это мнение субъективно.©


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 06, 2012, 12:53
Цитировать
Само по себе существование такого решения в мире программирования на C++ абсурдно. Есть субъективные мнения и не более. И даже это мнение субъективно.©
Почитайте про шаблонное метапрограммирование, в частности про шаблоны выражений в соседней ветки: http://www.prog.org.ru/topic_21540_0.html (http://www.prog.org.ru/topic_21540_0.html)
Как альтернатива вашему подходу, которую люди не просто так с потолка взяли и которая не на пустом месте стала очень популярным и мощным решением.


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 06, 2012, 13:13
Цитировать
Само по себе существование такого решения в мире программирования на C++ абсурдно. Есть субъективные мнения и не более. И даже это мнение субъективно.©
Почитайте про шаблонное метапрограммирование, в частности про шаблоны выражений в соседней ветки: http://www.prog.org.ru/topic_21540_0.html (http://www.prog.org.ru/topic_21540_0.html)
Как альтернатива вашему подходу, которую люди не просто так с потолка взяли и которая не на пустом месте стала очень популярным и мощным решением.
Я имел в виду, то, что в программирование вобще как в таковом очень мало случаев когда есть единственно верный вариант решения. А не то, что вы подумали и не то, куда вы меня отправили.


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 06, 2012, 13:20
Цитировать
Само по себе существование такого решения в мире программирования на C++ абсурдно. Есть субъективные мнения и не более. И даже это мнение субъективно.©
Почитайте про шаблонное метапрограммирование, в частности про шаблоны выражений в соседней ветки: http://www.prog.org.ru/topic_21540_0.html (http://www.prog.org.ru/topic_21540_0.html)
Как альтернатива вашему подходу, которую люди не просто так с потолка взяли и которая не на пустом месте стала очень популярным и мощным решением.
Я имел в виду, то, что в программирование вобще как в таковом очень мало случаев когда есть единственно верный вариант решения. А не то, что вы подумали и не то, куда вы меня отправили.
Я не говорю о единственно верном варианте. Я говорю, что вариант в методичке - это пример как проектировать не нужно. Это костыль, от которого можно (да, да, есть решения более изящные и гибкие) избавиться, но вам, видимо,    приятнее ходить на костылях, чем свободно передвигаться без них)
У меня ощущение, что вы всячески пытаетесь оправдать то, что с костылями ходить приятнее.. Но вы ведь даже не пробовали избавится от них.
О чём здесь ещё можно говорить?


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 06, 2012, 13:26
m_ax, ну Вы явно перегибаете палку. Хотим реализовать конструкцию
Код
C++ (Qt)
c = a + b;
 
Используя полиморфный механизм. Почему это плохо, кАстыльно (от слова "cast") ? :)  Во всей Вашей уничтожающей критике я не увидел ни одного мало-мальски весомого аргумента, а Ваши альтернативные предложения звучат странно. Ввести id типа - никак не в духе полиморфизма. Вынести операторы friend - и что, как это поможет с обобщенной алгеброй? 

Возможно template здесь более подходящий подход - согласен. Ну так "в огороде бузина, а в Киеве дядька". Чем виртуалы-то плохи? Я так вижу что только одним - что-то не получилось, не удалось сделать "по известным образцам", скопировать известное решение. И все - моментально срабатывает рефлекс "костыль! велосипед! посмотри на..". Грустно  :'(


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 06, 2012, 13:30
Мне тож гручтно  :'(

Путь кто нить приведёт пример нормального поведения (и полиморфного в том числе) для данной постановки задачи. Основываясь на тех рекомендациях, что приведены в методичке.

Потом я приведу свой вариант и сравним)


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 06, 2012, 14:37
И да, кстатии,
Цитировать
Хотим реализовать конструкцию

c = a + b;
 
Используя полиморфный механизм. Почему это плохо...
Я в курсе что мы это хотим реализовать. Именно с возможностью полиморфизма.
А плохо то, что вы пытаетесь писать костыль у которого больше минусов, чем плюсов, вместо того, что бы немного изменить архитектуру и тогда можно будет строить подобные конструкции, как используя полиморфизм:
Код
C++ (Qt)
AbstractNumber *n1 = new RealNumber(3.14);
AbstractNumber *n2 = new RealNumber(2.71);
 
*n1 = *n2 + *n1;
 

так и  использовать конструкции вида:
Код
C++ (Qt)
RealNumber n1(3.14);
RealNumber n2(2.71);
 
n1 = n2 + n1;
 
И всё это можно реализовать гораздо изящнее. И сами числа у вас, не с того не с сего, не будут менять свои значения при таких операциях.

Так что грустно, от того, что вы оправдываете  изначально кривую архитектуру.
А почему в методичке был поставлен так вопрос - это уже другая история (возможно печальная))
 


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 06, 2012, 19:16
Так что грустно, от того, что вы оправдываете  изначально кривую архитектуру.
А с чего вы собственно взяли, что архитектура кривая?


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 06, 2012, 21:02
Так что грустно, от того, что вы оправдываете  изначально кривую архитектуру.
А с чего вы собственно взяли, что архитектура кривая?
Вы что, издеваетесь надо мной? Перечитайте этот топик несколько раз)


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 06, 2012, 21:24
Реализацию я переписал, числа у меня значения при арифметических операциях не меняют. Мне проще написания обращения через указатели, чем через 3 класса, т.к. обращения к арифметическим операциям у меня идут в отдельном классе и упоминаются лишь единажды в проекте. Фактически ваш вариант займет физически больше кода. Есть еще у вас варианты в пользу использования вашего метода, а не кастования типов?


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 06, 2012, 21:27
Реализацию я переписал, числа у меня значения при арифметических операциях не меняют. Мне проще написания обращения через указатели, чем через 3 класса, т.к. обращения к арифметическим операциям у меня идут в отдельном классе и упоминаются лишь единажды в проекте. Фактически ваш вариант займет физически больше кода. Есть еще у вас варианты в пользу использования вашего метода, а не кастования типов?
Любопытно взглянуть) Не выложите исходники?


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 06, 2012, 22:11
Да, конечно. Вот, в первозданном виде.


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 06, 2012, 22:42
Да, конечно. Вот, в первозданном виде.
Поздравляю, Даниил! Вы действительно (худо-бедно) избавились от проблемы изменения чисел при мат. операциях над ними.
Вот только приобрели другую проблему... Даже и не знаю, какая из них страшней...


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 07, 2012, 03:10
А с чего вы собственно взяли, что архитектура кривая?
Ну вообще-то кривая :) Это называется "мнимая общность". Неск классов наследуются от Number, и это можно как-то оправдать, мол, "все эти классы - числа". Но если посмотреть а что же общего у этих классов - то выясняется что аж ничего. Нет ни одного метода который общий и имеет смысл напр как для PNumber так и для ComplexNumber. "Все они имеют оператор +", ну так в Assistant есть десятки (или больше) классов с таким оператором, но на этом основании они не наследуются от одного базового.

Но не стоит это воспринимать так трагически как делает m_ax  :) Это просто учебный пример, вполне возможен случай когда классы действительно имеют достаточно общего, виртуалов и сделать еще и операторы виртуальными может быть вполне разумно.

Да, конечно. Вот, в первозданном виде.
Ой  :)  Так у Вас "течет" память. Если оператор вернул класс по значению, то он автоматычно удалится когда станет ненужным. Но если оператор вернет ссылку - удалять ее никто не будет, и память (которую Вы выделили через new) не будет освобождена.


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 07, 2012, 14:10
Цитировать
Но не стоит это воспринимать так трагически как делает m_ax   Это просто учебный пример, вполне возможен случай когда классы действительно имеют достаточно общего, виртуалов и сделать еще и операторы виртуальными может быть вполне разумно.
:) Нет, я не драматизирую)
Кривость архитектуры здесь не в том, что они наследуются от "мнимой общности".. Фиг с ней, пусть наследуются - это как раз и даст им возможность полиморфизма.
Дело то в другом. Они пытаются забивать гвозди утюгом, в уверенности, что утюг для этого и создан.
Уже сам факт того, как они объявляют операторы+ - и др:
Код
C++ (Qt)
class Number
{
public:
// ...
   virtual Number& operator +(Number &n) = 0;
   virtual Number& operator -(Number &n) = 0;
   virtual Number& operator /(Number &n) = 0;
   virtual Number& operator *(Number &n) = 0;
//...  
};
 
говорит о том, что у автора в голове полное не понимание основ перегрузки операторов.. И авторитетность таких людей, которые ещё преподают c++, у меня под большим-большим сомнением.
В этом и проблема)


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 07, 2012, 14:29
говорит о том, что у автора в голове полное не понимание основ перегрузки операторов.. И авторитетность таких людей, которые ещё преподают c++, у меня под большим-большим сомнением.
В этом и проблема)
Как легко критиковать других :) Но такая критика только сваливает тему во флуд - и ничего больше


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 07, 2012, 14:47
говорит о том, что у автора в голове полное не понимание основ перегрузки операторов.. И авторитетность таких людей, которые ещё преподают c++, у меня под большим-большим сомнением.
В этом и проблема)
Как легко критиковать других :) Но такая критика только сваливает тему во флуд - и ничего больше
Нееет, мухи отдельно - котлеты отдельно)
Одно дело, когда такие архитектурные решения, в процессе обучения вояет сам обучающийся (что вполне нормально: все мы учимся на ошибках), а другое, когда такие решения навязывают, выдавая за правильные, преподы.
Так вот потихоньку и разваливается наше классическое образование.. Вы меня понимаете?   


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 07, 2012, 15:03
Так вот потихоньку и разваливается наше классическое образование.. Вы меня понимаете?   
Милости просим в министерство образования с инновационными идеями.


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 07, 2012, 15:04
Так вот потихоньку и разваливается наше классическое образование.. Вы меня понимаете?   
Милости просим в министерство образования с инновационными идеями.
Вообще то, вы в этом должны быть больше заинтересованы, не находите?


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 07, 2012, 15:06
Так вот потихоньку и разваливается наше классическое образование..
При всем желании никак не могу назвать свое образование классическим. Нет, ну формально я программирование изучал, но тогда рулили транзисторы и операционные усилители, а этот курс АЯиП никаким авторитетом не пользовался. Лектор был рыжий и один раз даже пришел на лекцию с яйцами (в смысле с лотком), всякому было ясно что программист - женщина и скоро уйдет в декрет.

Так что по сравнению с тем что было - не так уж плохо, чего Вы напустились? И вообще - хватит порожняк гонять с учебным примером,  для Вас есть напр такое

http://www.prog.org.ru/index.php?topic=21481.msg148890#msg148890 (http://www.prog.org.ru/index.php?topic=21481.msg148890#msg148890)

А то повыучивали тут паттерны всякие..


Название: Re: Реализация интерфейса
Отправлено: Даниил от Апрель 07, 2012, 18:18
Вообще то, вы в этом должны быть больше заинтересованы, не находите?
Дабы вы успокоились, скажу вам, что преподаватель выразил такую же идею - что именно перегружать операторы (+,-, /,*) не самая лучшая идея для данного решения. Но задумка была именно в dynamic_cast и кривизна решения тут мера необходимая. Просто для того, чтобы студенты думали головой и пытались найти лучшее решение в проигранной ситуации.
А так да, он всерьез задумался о том, чтобы переписать методички.


Название: Re: Реализация интерфейса
Отправлено: m_ax от Апрель 07, 2012, 18:34
Вообще то, вы в этом должны быть больше заинтересованы, не находите?
Дабы вы успокоились, скажу вам, что преподаватель выразил такую же идею - что именно перегружать операторы (+,-, /,*) не самая лучшая идея для данного решения. Но задумка была именно в dynamic_cast и кривизна решения тут мера необходимая. Просто для того, чтобы студенты думали головой и пытались найти лучшее решение в проигранной ситуации.
А так да, он всерьез задумался о том, чтобы переписать методички.
Идея тут не столько в dynamic_cast, а в том, чтобы на примере чисел продемонстрировать полиморфное поведение.
И этого эффекта можно добиться. И будет у вас возможность делать, например так:
Код
C++ (Qt)
Number *n1 = new TANumber;
Number *n2 = new TANumber;
 
*n1 = *n1 + *n2;
*n1 = *n1 - *n2;
*n1 = (*n1) * (*n2);
// ...
// и даже так:
TANumber n1;
TANumber n2;
 
n1 = n1 + n2;
n1 = n1 - n2;
// ...
 
 
Просто нужно вынести операторы + - * / из класса, а не пытаться делать их его членами.

ЗЫ Ну вы меня успокоили) Преподу привет от Russia Qt Forum)
ЗЫЗЫ Мы следим за качеством методичек  8)


Название: Re: Реализация интерфейса
Отправлено: Tonal от Апрель 09, 2012, 08:31
...
И пользоваться только AllNumber. :)
Ну "пользоваться только" - это несолидно.
ИМХО, в программировании нет аргумента «несолидно».
Есть лучше/хуже соответствует задаче, например. :)

А почему не так
Код
C++ (Qt)
struct CFractNumber : public CBaseNumber {
 CFractNumber & operator + (const CBaseNumber & other) const
 {
   assert(dynamoc_cast <const CFactNumber *> &other) != 0);
   CFractNumber & result = mBuf[mBufCount];
   result = *this;
   mBufCount = (mBufCount + 1) % BUF_SIZE;
   return result += other;
 }
 
 private:
   static int mBufCount = 0;
   static CFractNumber mBuf[BUF_SIZE];
 
   enum {
     BUF_SIZE = 256,
   };
};
 
Потому что не контролируется переполнение :)
Код
C++ (Qt)
CFractNumber fun1(const CFractNumber& init, int cnt) {
 CFractNumber& res = init + init;
 for (int i = 0; i < cnt - 1; ++i)
   res = res + init;
 return res;
}
// или чуть подругому:
CFractNumber fun2(const CFractNumber& init, int cnt) {
 const CFractNumber& first = init + init;
 CFractNumber res = first;
 for (int i = 0; i < cnt - 1; ++i)
   res = res + init + first;
 return res;
}
//И где-то в коде:
CFractNumber b = fun1(a, 1000);
CFractNumber d = fun2(c, 1000);
 
По сути отличается от моего кода только распределением памяти и контролем за ней.
Ежели можешь рассчитать верхний предел одновременного количества временных объектов, и приделать гарантию, что они не пересекутся, то можно и так. :)


Название: Re: Реализация интерфейса
Отправлено: Igors от Апрель 09, 2012, 08:57
Потому что не контролируется переполнение :)
То да, и возвращение константной ссылки не спасает. Причем не видно даже как отловить - ведь деструктор не будет вызван если вернули ссылку. Ну ладно, все имеет минусы