Я использую две сторонние библиотеки, каждая из которых реализует собственный 2D-векторный класс. К сожалению, мне приходится работать с ними обоими, так что могу ли я в любом случае написать некоторые «дружественные» функции, чтобы одну можно было автоматически преобразовать в другую, когда я пытаюсь использовать их в функциях из другой библиотеки?
Автоматически применять два сторонних класса?
Ответы (3)
Операторы преобразования должны быть функциями-членами.
В подобных ситуациях я использовал шаблон функции convert<X,Y>
с полной специализацией или перегрузками для каждой пары типов, которые я хочу "преобразовать". В этом случае вам не понадобится шаблон, только две перегрузки, по одной в каждом направлении, потому что для данного X есть только одна вещь, в которую вы его конвертируете.
Тогда редко возникает проблема переключения между одним и другим (заметным исключением является случай, когда вы используете код шаблона, который требует, чтобы один тип параметра был преобразован в другой). Вы можете легко увидеть в коде границу между двумя API, не внося особого шума.
Причина, по которой я часто сталкивался с этой ситуацией, заключается в написании уровней абстракции ОС: базовая ОС имеет один набор объектов или непрозрачных дескрипторов для различных концепций ОС, а API, который вы реализуете, имеет другой. Гораздо приятнее просто «преобразовать» один набор концепций в другой, не имея ConvertHostMutexToGuestMutex, ConvertGuestMutexToHostMutex, ConvertHostSocketOptsToGuestSocketOpts и т. д. Недостатком является обычный недостаток с широко распространенной перегрузкой, то есть не обязательно очевидно, где функции фактически определены.
Автоматическая-трансляция кажется невозможной. Вы можете определить глобальную функцию преобразования и вызвать ее явно. Не могли бы вы опубликовать определение этих классов? Может получится какой-то трюк с наследованием.
Что-то вроде этого, но это не автоматическое литье:
class T1 {};
class T2 {};
class UnionType : public T1, public T2
{
public:
UnionType( const T1& val ) {} // real storing should be here
UnionType( const T2& val ) {} // real storing should be here
operator T1() { T1 t; return t; } // real conversion should be here
operator T2() { T2 t; return t; } // real conversion should be here
};
int main()
{
T1 t;
T2 t2 = UnionType(t);
return 0;
}
Одним из способов было бы наследование от этих классов и предоставление операторов преобразования друг для друга. Но тогда вам придется использовать объекты производного класса в своем коде. Вот пример кода:
class ThirdParty1
{
public:
ThirdParty1(int x, int y) : m_x(x), m_y(y)
{
}
int getX() const { return m_x; }
int getY() const { return m_y; }
private:
int m_x;
int m_y;
};
class ThirdParty2
{
public:
ThirdParty2(int x, int y) : m_x(x), m_y(y)
{
}
int getX() const { return m_x; }
int getY() const { return m_y; }
private:
int m_x;
int m_y;
};
template<class Type, class AdaptedType>
class TP1Adaptor : public Type
{
public:
TP1Adaptor(int x, int y): Type(x,y)
{
}
operator AdaptedType()
{
return AdaptedType(getX(),getY());
}
};
typedef TP1Adaptor<ThirdParty1, ThirdParty2> First2D;
typedef TP1Adaptor<ThirdParty2, ThirdParty1> Second2D;
void f(ThirdParty1 tp)
{
}
void f1(ThirdParty2 tp)
{
}
int main()
{
First2D f(0,0);
f1(f);
return 0;
}