Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Cast Problem :-/

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
09.04.2006, 20:33 Uhr
mike
Pinguinhüpfer
(Operator)


Hallo
Mein Compiler mag mich nicht ...
Ich habe folgende Klasse
CalcOperator
\_ CalcOpAddition
\_ CalcOpSubtraction
\_ CalcOpMultiplication
\_ CalcOpDivison

Die Klassen habe alle iene abstrakte Methode:
Execute(double first, double second, double &result);

Ich möchte jetzt einen Funktionhandler machn der mir die richtige Operationa auruft:

C++:
theCalcOpAddition_ = new CalcOpAddition;
theCalcOpSubtraction_ = new CalcOpSubtraction;
theCalcOpMultiplication_ = new CalcOpMultiplication;
theCalcOpDivison_ = new CalcOpDivison;

AddOperand("+", &theCalcOpAddition_);
...




C++:
// *.h
typedef void (*OpPtr) (CalcOperator &);
....
map<std::string, OpPtr> operandHandler_;



C++:
//*.cpp
void CalcKernel::DispatchOperand(const std::string operand, double first, double second, double result)
{  
  map<string, OpPtr>::iterator it = operandHandler_.find(operand);
  if(it != operandHandler_.end()) {
    it->second(....); // <-----
    dynamic_cast<...>; // <----
   }
   else
     cout << "Operand not found" << endl;
}

void CalcKernel::AddOperand(const std::string& Name, OpPtr Function)
{
  operandHandler_[Name] = Function;
}



Nun ist mein Problem die markierten Zeilen. Ich hab mir überlegt, AddOperand den Cast-Typ (also die Klasse) mit zu übergeben. Aber ich hänge jetzt voll ...

Ziel ist es also, Rechenoperationen dynamisch hinzufügen zu können. Der Aufruf soll dann so ausschaun:
DispatchOperand("+", 12, 5, result);
result soll dann 17 sein - die entsprechende Klasse (CalcOpAddition) soll die Operation ausführen.

Danke im Voraus,
lg
--
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
09.04.2006, 22:08 Uhr
Spacelord
Hoffnungsloser Fall


Hallo mike,
ich kann nicht so ganz nachvollziehen was genau du da mit dem Funktionszeiger vorhast aber ich hab hier mal nen stark vereinfachtes Beispiel geschrieben das in die Richtung geht was du anscheinend machen möchtest.
Innerhalb von DispatchOperand gibt es keinen Grund etwas zu casten.Da kannst du die virtuelle Methode execute für dich arbeiten lassen.
In der map hab ich anstelle der Funktionspointer Zeiger auf CalcOperator Instanzen genommen.
Die execute Methoden der konkreten Instanzen machen dann automatisch das Richtige,ohne dass du irgendwas casten musst.
Das Ganze ist teilweise recht unschön.Ich hab mich da jetzt aber weitestgehend an deine Vorgaben gehalten und mich lediglich auf das Kernproblem beschränkt.
Verbesserungen wären der Einsatz von boost::shared_ptr und nen double als Rückgabewert von execute zurückzugeben anstatt nen double als inOut Parameter reinzureichen.

Wie dem auch sei....

C++:
#include<iostream>
#include<string>
#include <map>

using namespace std;

class CalcOperator
{
public:
    CalcOperator(){}
    virtual ~CalcOperator(){}
    virtual void execute(double first, double second, double &result)=0;
};

struct CalcOpAddition:public CalcOperator
{
public:
    void execute(double first, double second, double &result)
    {
        result = first+second;
    }
};

struct CalcOpSubtraction:public CalcOperator
{
public:
    void execute(double first, double second, double &result)
    {
        result = first-second;
    }
};

class CalcKernel
{
    typedef std::map<char,CalcOperator*> dispatch_map;
    dispatch_map operandHandler_;
public:
    ~CalcKernel()
    {
        dispatch_map::iterator it = operandHandler_.begin();
        while(it != operandHandler_.end())
        {
            delete (*it).second;
            ++it;
        }
    }
    void CalcKernel::DispatchOperand(char op, double first, double second, double& result)
    {  
        dispatch_map::iterator it = operandHandler_.find(op);
        if(it != operandHandler_.end())
            (*it).second->execute(first,second,result);
        else
            cout << "Operand not found" << endl;
    }

    void CalcKernel::AddOperand(const char op, CalcOperator* calcOP_p)
    {
      operandHandler_[op] = calcOP_p;
    }
};



int main()
{
    CalcKernel kernel;
    CalcOperator* theCalcOpAddition_ = new CalcOpAddition;
    CalcOperator* theCalcOpSubtraction_ = new CalcOpSubtraction;
    kernel.AddOperand('+',theCalcOpAddition_);
    kernel.AddOperand('-',theCalcOpSubtraction_);
    double res=0;
    kernel.DispatchOperand('+',1.2,1.3,res);
    cout<<"1.2 + 1.3 = "<<res<<endl;
    kernel.DispatchOperand('-',2.5,1.2,res);
    cout<<"2.5 - 1.2 = "<<res<<endl;
  
    return 0;
}



Gruss Spacelord
--
.....Ich mach jetzt nämlich mein Jodeldiplom.Dann hab ich endlich was Eigenes.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
10.04.2006, 09:46 Uhr
mike
Pinguinhüpfer
(Operator)


Perfekt

Danke für die Mühe & das ausführliche Sample - haut super hin!!!!
An die Möglichkeit DispatchOperand so zu schreiben hab ich gar nicht gedacht

Bis dann
lg
--
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
10.04.2006, 11:54 Uhr
(un)wissender
Niveauwart


Wobei hier

C++:
void CalcKernel::AddOperand(const char op, CalcOperator* calcOP_p)
    {
      operandHandler_[op] = calcOP_p;
    }


memory leaks warten. Wenn operandHandler_[op] schon belegt ist, dann wird der alte nicht gelöscht, sondern nur überschrieben.
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
10.04.2006, 21:39 Uhr
mike
Pinguinhüpfer
(Operator)


thx. stimmt - sollte man zuerst überprüfen
--
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
10.04.2006, 22:15 Uhr
Spacelord
Hoffnungsloser Fall


Hi,
an dieser Stelle sei noch erwähnt dass deine ganzen Operator Klassen im Grunde schon Bestandteil des Standards sind.
Da gibt es die von binary_function abgeleiteten Klassen plus,minus etc. die letztendlich das Gleiche machen.
Das Problem ist nur,dass diese alle nen anderen Typ haben und du diese nicht so ohne weiteres als zweiten Wert deiner map Paare nehmen kannst.
Abhilfe schafft da boost::function.
function ist nen Wrapper für Funktionen,Funktoren etc.
function schluckt alles was die angegebenen Argumente akzeptiert und den richtigen Rückgabewert hat.
Damit kannst du dann mit bedeutend weniger Code ne generische Klasse anlegen mit der du z.B. auch mit komplexen Zahlen rechnen kannst.

C++:
#include<iostream>
#include<string>
#include <map>
#include <complex>
#include "boost\\function.hpp"

using namespace std;

template <class T>
class CalcKernel
{
    typedef std::map<char,boost::function<T(T,T)> > dispatch_map;
    dispatch_map _map;
public:
    T DispatchOperand(char op,T first_arg,T second_arg)
    {  
        T result = T();
        dispatch_map::iterator it = _map.find(op);
        if(it != _map.end())
            result = (*it).second(first_arg,second_arg);
        else
            cout << "Operand not found" << endl;
        return result;
    }
    void AddOperand(const char op, boost::function<T(T,T)> _func)
    {
        _map.insert(std::make_pair(op, _func));
    }
};

template <class T>
void init_basic_operators(CalcKernel<T> &k)
{
    k.AddOperand('+',boost::function<T(T,T)>(std::plus<T>()));
    k.AddOperand('-',boost::function<T(T,T)>(std::minus<T>()));
    k.AddOperand('/',boost::function<T(T,T)>(std::divides<T>()));
    k.AddOperand('*',boost::function<T(T,T)>(std::multiplies<T>()));
}

int main()
{
    CalcKernel<double> kernel;
    init_basic_operators(kernel);
    cout<<"1.2 + 1.3 = "<<kernel.DispatchOperand('+',1.2,1.3)<<endl;
    cout<<"2.5 - 1.2 = "<<kernel.DispatchOperand('-',2.5,1.2)<<endl;
    cout<<"3.33 / 1.11 = "<<kernel.DispatchOperand('/',3.3,1.1)<<endl;
    cout<<"2.5 * 5.6 = "<<kernel.DispatchOperand('*',2.5,5.6)<<endl;
    
     //Und nen CalcKernel für komplexe Zahlen
    CalcKernel<std::complex<double> > complex_kernel;
    init_basic_operators(complex_kernel);
    complex<double> c1(1.3,2.4);
    complex<double> c2(3.4,2.1);
    cout<<"c1 + c2 = "<<complex_kernel.DispatchOperand('+',c1,c2)<<endl;

    return 0;
}


Gruss Spacelord
--
.....Ich mach jetzt nämlich mein Jodeldiplom.Dann hab ich endlich was Eigenes.

Dieser Post wurde am 10.04.2006 um 22:20 Uhr von Spacelord editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: