Operatoren und abgeleitete Klassen
-
Guten Tag,
ich habe folgendes Problem. Für einen Interpreter benötige ich
verschiedene Variablentypen. Das können z.B. double, int oder auch chars sein.
Diese Variablen möchte ich in Klassen Kapseln welche alle vom Ursprungstyp CVariable sind (also abgeleitet).
Im späteren Verlauf möchte ich diese abgeleitete Typen untereinander verlgeichen oder verrechnen. Hierzu implementiere ich die entsprechenden operatoren in den abgeleiteten Klassen. Dies sieht dann wie folgt aus:#ifndef _TYPES_H_ #define _TYPES_H_ class CVariable { public: CVariable(){} private: }; // class prototype class CInteger; class CDouble : public CVariable { // friends friend class CDouble; friend class CInteger; public: CDouble(double dValue) : m_dValue(dValue){} CDouble(const CInteger& val); CDouble(const CDouble& val); // operators virtual CDouble operator*(const CDouble& Val) const; virtual CDouble operator*(const CInteger& Val) const; private: CDouble(); double m_dValue; }; class CInteger : public CVariable { public: friend class CInteger; friend class CDouble; CInteger(int iValue) : m_iValue(iValue){} CInteger(const CDouble& val); CInteger(const CInteger& val); // operators virtual CInteger operator*(const CDouble& Val) const; virtual CInteger operator*(const CInteger& Val) const; private: CInteger(); int m_iValue; }; #endif // Implementierung #include "Types.h" CDouble CDouble::operator*(const CDouble& Val) const { return CDouble(m_dValue * Val.m_dValue); } CDouble CDouble::operator*(const CInteger& Val) const { return CDouble(m_dValue * Val.m_iValue); } CDouble::CDouble(const CInteger& val) { m_dValue = val.m_iValue; } CDouble::CDouble(const CDouble& val) { m_dValue = val.m_dValue; } CInteger CInteger::operator*(const CDouble& Val) const { return CInteger(m_iValue * Val.m_dValue); } CInteger CInteger::operator*(const CInteger& Val) const { return CInteger(m_iValue * Val.m_iValue); } CInteger::CInteger(const CDouble& val) { m_iValue = static_cast<int>(val.m_dValue); } CInteger::CInteger(const CInteger& val) { m_iValue = val.m_iValue; } // main int _tmain(int argc, _TCHAR* argv[]) { CVariable *pFirst,*pSecond,*pRes; pFirst = new CDouble(1.23); pSecond = new CDouble(2.22); pRes = new CDouble(0); /* so funktioniert es */ *static_cast<CDouble*>(pRes) = *static_cast<CDouble*>(pFirst) * *static_cast<CDouble*>(pSecond); /* so nicht */ *pRes = *pFirst * *pSecond; return 0; }Wie in Main gezeigt funktioniert das ganze auch wenn ich zuvor die Typen auf entsprechend Caste. Das würde ich aber gerne vermeiden. Mir ist auch klar dass die Basisklasse die entsprechenden prototpyen der abgeleitetn Klasse nicht kennt, also dessen Operatoren.
Ich vermute der Ansatz wird schon entsprechend verkehrt sein.
Wenn jemand eine gute Idee hat wäre ich sehr dankbar.Gruß
Holger
-
Hi,
Diese Problematik, wie auch das Klassendesign, lässt sich mit Templates Lösen.
Der folgende Code erfordert, einen Compiler mit C++0x Unterstützung. Falls du keinen hast musst du dir die type_traits selbst zusammenbasteln oder auf Boost::type_traits zurückgreifen.#include <typeinfo> #include <type_traits> #include <iostream> template<typename T=void> struct Variable; template<> struct Variable<>{}; //missbrauche ich mal als Parent und Identifier template<typename T> struct Variable : Variable<> { typedef T Type; Type Data; Variable()=default; Variable(T const& D): Data{D} {} template<typename T2> Variable(Variable<T2> const& D): Data{(T)D.Data} {} template<typename T2> Variable<T>& operator=(Variable<T2> const& RHS) { this->Data = RHS.Data; return *this; } template<typename T2> Variable<T>& operator+=(Variable<T2> const& RHS) // operator+ global über += implementieren { this->Data+=static_cast<T>(RHS.Data); return *this; } }; struct Integer2 : public Variable<int> { //using Variable<int>::Variable; leider noch nicht unterstützt Integer2(int const& D): Variable<int>(D) {} template<typename T2> Integer2(Variable<T2> const& D): Variable<int>(D) {} }; //Template-Magie ;-) template<typename A , typename B> struct DeclType { A a; B b; typedef decltype( a + b ) Type; }; template<class lhs ,class rhs> typename std::enable_if< std::is_base_of<Variable<>,lhs>::value && std::is_base_of<Variable<>,rhs>::value, Variable< typename DeclType<typename lhs::Type,typename rhs::Type>::Type > >::type operator+(lhs const& LHS, rhs const& RHS) { return Variable< typename DeclType<typename lhs::Type,typename rhs::Type>::Type >(LHS.Data+RHS.Data); } int main() { Variable<int> I{1}; Variable<float> B(3.14); Integer2 I2(3); I=2; auto X= I + B + I2; std::cout<< I.Data<<" + " <<B.Data<<" = "<< X.Data; }Wirst du anschliesend noch Strukturen darstellen wollen, empfehle ich Variable auf Variadic Templates aufzurüsten.
MFG Speed
-
Das können z.B. double, int oder auch chars sein.
Diese Variablen möchte ich in Klassen Kapseln welche alle vom Ursprungstyp CVariable sind (also abgeleitet).Typische Interpreter loesen das mittels Union.
-
Das Problem was du mit den Vergleichen über die Basisklasse hast, nennt sich double Dispatch - schau mal ob du da bei google was findest
