Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   С/С++, C#, Delphi, .NET, Asm (https://forum.antichat.xyz/forumdisplay.php?f=24)
-   -   Жёсткая задачка про ООП в С++ (https://forum.antichat.xyz/showthread.php?t=42164)

pch 14.06.2007 00:16

Жёсткая задачка про ООП в С++
 
Прелюдия (можно смело пропустить)
Вообщем хочется написать класс полиномов над некоторым типом aType так, чтобы операции были понолстью френд-перегружены, т.е. чтобы работало int==Polynom<int>, int*Polynom<int> и другие приятности.
В не-шаблонном случае это - тривиальнейшая задача. Как только я ввожу шаблоны, aType престаёт приводиться к Polynom, хотя конструктор Polynon<int> имеется. Если выкинуть контекст, и оставить только саму проблему, то получится

Задача
Заставить работать парой волшебных пассов
Код:

#include <iostream>
using namespace std;

template <class aType>
class testClass{
public:
      aType data;
      testClass(aType c): data(c) {}
      bool friend operator==<aType>(testClass<aType>, testClass<aType>);
};
template <class aType>
bool operator==(testClass<aType> a, testClass<aType> b){
      return a.data==b.data;
}
int main(){
      int a=4;
      testClass<int> b(4);
      if (a==b) cout << "a equals b\n";
      if (b==a) cout << "b equals a\n";
}

В таком состоянии выдает две ошибки:
Код:

no match for `testClass<int> & == int &`
no match for `int & == testClass<int> &`

Если вызывать явные конструкторы Polynom(a)==b, всё работает, но тогда инкапсуляция и всё изящество идёт лесом.

Действительно хоть какое-то решение - делать приведения явно, но внутри класса. Т.е. добавив
Код:

     
bool friend operator==<aType>(aType a, testClass b<aType>);
bool friend operator==<aType>(testClass a<aType>, aType b);

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

_Great_ 14.06.2007 00:59

Ну ясен пень, ты сравниваешь целое число и объект класса. У тебя же нет оператора их сравнения. Кстати, что за компилер? Обычно такое компилеры кушают, создавая временные объекты.. хотя хз, я точно не знаю

Aag 14.06.2007 11:26

По-моему, просто надо реализовать соответствующий оператор копирования, поскольку по умолчанию генерируется такой оператор копирования
Код:

testClass<aType>& testClass<aType>::operator = (const testClass<aType>& hs)
вам для неявного преобразования надо реализовать такой оператор класса, который в качестве аргумента принимает не testClass<aType>& , а аргумент aType &
Код:

testClass<aType>& testClass<aType>::operator = (const aType& hs){
    data = hs;
    return *this;
};


pch 14.06.2007 12:19

2 _Great_
У меня есть функция сравнения двух объектов класса testClass<int> и есть котструктор testClass<int>(int). Так что компилятор может привети оба операнда к типу testClass<int> и сравнить. Более того, если выкинуть все шаблоны и везде заменить aType на int (а testClass<int> b(4) на testClass b(4)), то всё именно так и работает.
Компялятор - gcc (win).

2 Aag
А где здесь копирование? Я же иницаализирую не элементом того же класса, а int-ом...
В любом случае, добавление явного оператора копирования ничего не меняет, те же ошибки

Aag 14.06.2007 23:07

Компильнул твой код из начала темы. Ни одной ошибки. Все работает без изменений.
Получил
Код:

a equals b
b equals a

Копилятор gcc 3.3.5 (*nix)

про оператор присваивания я не прав. здесь действительно инициализация идет.

pch 15.06.2007 01:08

Пробовал на:
BSD: gcc version 3.4.2 [FreeBSD] 20040728
Linux: gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
Win: gcc version 2.95.2 19991024 (release)
Win: gcc version 3.4.2 (mingw-special)

И вcе выдают более-менее одну и ту же ошибку.

Это однако ппц какой-то.
Можете привести что точно выводит это компилятор на gcc -v ? Мож там ключи какие хитрые подефолту?

Aag 15.06.2007 15:36

gcc -v: gcc version 3.3.5

Попробывал на mingw 3.4.5 под win действительно не работает.

Но при минимальных изменениях все работает под mingw 3.4.5
Код:

#include <iostream>

template <typename aType>
class testClass{
public:
      aType data;
      testClass(aType c): data(c) {};
      bool friend operator==(testClass<aType> a, testClass<aType> b){return a.data==b.data;} ;
};


int main(){
      int a=4;
      testClass<int> b(4);
      if (a==b) std::cout << "a equals b\n";
      if (b==a) std::cout << "b equals a\n";
};

то есть если внести описания друга внутрь класса.

Вот посмотри еще http://en.wikipedia.org/wiki/Barton-Nackman_trick

pch 15.06.2007 17:00

Ух-ты. Я просто в Ахуе. Огромный респект!

ZaCo 16.06.2007 15:36

:) а так по-моему много проще:
operator int()
{
return data;
}

pch 16.06.2007 16:00

2 ZaCo

Ну тогда уж не operator int(), а operator aType(), но в любом случае это - не то ;) . Этот оператор преобразует оба операнда к типу aType (в данном случае - int), и сравнивает их как инты. А если в классе не одно поле (например, рац числа над типом int), то приведение к инту даст лажу (можно приводить в частном случае к флоату, но в общем шаблонном случае непонятно к чему приводить).

Убедиться, что оператор сравнения в классе testClass lдействительно не вызывается просто, достаточно добавить туда cout:
Код:

#include <iostream>
using namespace std;

template <class aType>
class testClass{
public:
        aType data;
        testClass(aType c): data(c) {}
        bool friend operator==<aType>(testClass<aType>, testClass<aType>);
        operator aType(){
                return data;
        }
};
template <class aType>
bool operator==(testClass<aType> a, testClass<aType> b){
        cout << "Operator == exucuted\n";
        return a.data==b.data;
}
int main(){
        int a=4;
        testClass<int> b(4);
        if (a==b) cout << "a equals b\n";
        if (b==a) cout << "b equals a\n";
}

Этот код не выведет фразу "Operator == exucuted" ни разу


Время: 12:45