Problem bei Funktionszeiger!



  • pat.de schrieb:

    Die Frage ist nur, ob deine Vorgaben die Benutzung externer Bibliotheken erlauben, oder darfst du benutzen, was du willst?

    ich kann mich da ganz frei bewegen, aber mir persönlich wäre es lieber auf die standard libary zuzugreifen.

    Ev. ist deine Kompiler / Library schon so weit, dass er TR1 Dinge von C++11 unterstützt, z.B. std::function<...> bzw. std::tr1::function<...>



  • pat.de schrieb:

    Cmd* mass_erase= new Cmd("set_startaddr", 1, 1, &Flash_cmds::getInstance().setStartaddr);
    

    Da holst du dir die addresse von einer funktion einer instanz die du vom statischem context entnimmst.
    Ich würde mal sage, wenn setStartAddr eine funktion von Flash_cmds ist: &Flash_cmds::setStartAddr()
    Dann kannst du das so aufrufen:
    (Flash_cmds::getInstance()->*setStartAddr)(arugumentenliste wie gewohnt);

    http://www.parashift.com/c++-faq-lite/pointers-to-members.html



  • // Abstrakte Basisklasse für alle möglichen Commands
    class Command
    {
    public:
    	virtual ~Command()
    	{
    	}
    
    	void operator()()
    	{
    		execute();
    	}
    
    private:
    	virtual void execute() = 0;
    };
    
    // Implementation für non-member Funktion mit einem Argument
    template<typename ResultType, typename ArgumentType>
    struct CommandNM1 : Command
    {
    	typedef ResultType( *FuncPtr)( ArgumentType );
    
    	ResultType 				Result;
    	ArgumentType 			Argument;
    	FuncPtr					Function;
    
    	CommandNM1( FuncPtr Func, ArgumentType Arg ) :
    		Function( Func ),
    		Argument( Arg ),
    		Result( ResultType() )
    	{
    	}
    
    	virtual void execute()
    	{
    		Result = Function( Argument );
    	}
    };
    
    // Spezialisierung für non-member Funktionen mit einem Argument und ohne Rückgabewert
    template<typename ArgumentType>
    struct CommandNM1<void,ArgumentType> : Command
    {
    	typedef void( *FuncPtr)( ArgumentType );
    
    	ArgumentType 			Argument;
    	FuncPtr					Function;
    
    	CommandNM1( FuncPtr Func, ArgumentType Arg ) :
    		Function( Func ),
    		Argument( Arg )
    	{
    	}
    
    	virtual void execute()
    	{
    		Function( Argument );
    	}
    };
    
    template<typename ResultType, typename ArgumentType>
    Command* make_command( ResultType (*Func)( ArgumentType ), ArgumentType Arg )
    {
    	return new CommandNM1<ResultType,ArgumentType>( Func, Arg );
    }
    
    // Implementation für member Funktion mit einem Argument
    template<typename ObjectType, typename ResultType, typename ArgumentType>
    struct CommandM1 : Command
    {
    	typedef ResultType( ObjectType::*FuncPtr)( ArgumentType );
    
    	ResultType 				Result;
    	ArgumentType 			Argument;
    	FuncPtr					Function;
    	ObjectType&				Object;
    
    	CommandM1( ObjectType& Obj, FuncPtr Func, ArgumentType Arg ) :
    		Function( Func ),
    		Object( Obj ),
    		Argument( Arg ),
    		Result( ResultType() )
    	{
    	}
    
    	virtual void execute()
    	{
    		Result = (Object.*Function)( Argument );
    	}
    };
    
    template<typename ObjectType, typename ResultType, typename ArgumentType>
    Command* make_command( ObjectType& Obj, ResultType (ObjectType::*Func)( ArgumentType ), ArgumentType Arg )
    {
    	return new CommandM1<ObjectType,ResultType,ArgumentType>( Obj, Func, Arg );
    }
    
    void x( double y )
    {
    	int z = 0;
    }
    
    int f( double x )
    {
    	return x;
    }
    
    struct t
    {
    	int f( double x )
    	{
    		return x;
    	}
    };
    
    int main()
    {
    	t theT;
    	Command* c1 = make_command( f, 101.101 );
    	Command* c2 = make_command( theT, &t::f, 101.101 );
    	Command* c3 = make_command( x, 101.101 );
    
    	(*c1)();
    	(*c2)();
    	(*c3)();
    }
    

    Hab mal was (nur so aus der Hüfte geschossen) gebastelt, was du benutzen könntest. Statt roher Zeiger wären smart pointer toll, eventuell kann man mit boost/TR1::function das noch schöner machen. Aber als Hinweis taugt´s allemal was.



  • Ev. ist deine Kompiler / Library schon so weit, dass er TR1 Dinge von C++11 unterstützt, z.B. std::function<...> bzw. std::tr1::function<...>

    ich hab den gcc compiler drauf version 4.4.5

    Da holst du dir die addresse von einer funktion einer instanz die du vom statischem context entnimmst.
    Ich würde mal sage, wenn setStartAddr eine funktion von Flash_cmds ist: &Flash_cmds::setStartAddr()
    Dann kannst du das so aufrufen:
    (Flash_cmds::getInstance()->*setStartAddr)(arugumentenliste wie gewohnt)

    das klappt nicht so ganz...

    also bei

    Cmd* set_startaddr= new Cmd("set_startaddr", 1, 1, &Flash_cmds::getInstance()->*setStartaddr);
    

    kommt der fehler: Fehler 1 error C2065: 'setStartaddr': nichtdeklarierter Bezeichner

    ist das so richtig implementiert....

    Cmd.h

    #include <iostream>
    #include <string>
    #include "string.h"
    #include "Flash_cmds.h"
    
    #pragma once
    
    class Cmd
    {
    private:
    
    	std::string cmd_name;
    	std::string cmd_arg;
    	int cmd_id;
    	int cmd_argcount;
    	void (*cmd_exe)(void);
    	void (Flash_cmds::*cmd_exe_arg)(const int& t );
    
    public:
    	Cmd(void);
    	~Cmd(void);
    	Cmd(std::string name, int id, int argcnt, void (*execute_function)(void));
    	Cmd(std::string name, int id, int argcnt, void (Flash_cmds::*execute_function)(const int&));
    
    	std::string GetName(void)const;
    	int GetArgCount(void)const;
    
    	void setArg(const std::string& arg);
    
    	void Execute (void) const;
    
    	bool operator==(const std::string& cmd)const
    	{
    		return(this->GetName()==cmd);
    	}
    };
    

    Cmd.cpp

    #include "Cmd.h"
    
    Cmd::Cmd(void)
    {
    }
    
    Cmd::Cmd(const std::string name, const int id, const int argcnt,void (*execute_function)(void) )
    : cmd_name(name), cmd_id(id), cmd_argcount(argcnt), cmd_exe(execute_function)
    {
    	if (argcnt<0)
    	{	
    		std::cout<<"Ungueltige Anzahl von Argumenten"<<std::endl;
    		cmd_argcount=0;
    	}
    
    }
    
    Cmd::Cmd(const std::string name, const int id, const int argcnt, void (Flash_cmds::*execute_function)(const int& t) )
    : cmd_name(name), cmd_id(id), cmd_argcount(argcnt),cmd_exe_arg(execute_function)
    {
    	if (argcnt<0)
    	{	
    		std::cout<<"Ungueltige Anzahl von Argumenten"<<std::endl;
    		cmd_argcount=0;
    	}
    
    }
    
    Cmd::~Cmd(void)
    {
    }
    
    std::string Cmd::GetName (void) const
    {
    	return Cmd::cmd_name;
    }
    
    int Cmd::GetArgCount (void) const
    {
    	return Cmd::cmd_argcount;
    }
    
    void Cmd::Execute (void) const
    {
    	if(cmd_argcount==1)
    		;//cmd_exe_arg(500);
    	else
    		cmd_exe();
    }
    
    void Cmd::setArg(const std::string& arg)
    {
    	cmd_arg=arg;
    }
    

    ...?



  • ich hab den gcc compiler drauf version 4.4.5

    Der hat AFAIK std::tr1::function<..> drin. Die würde ich auch benutzen!



  • DocShoe schrieb:

    // Abstrakte Basisklasse für alle möglichen Commands
    class Command
    {
    public:
    	virtual ~Command()
    	{
    	}
    
    	void operator()()
    	{
    		execute();
    	}
    
    private:
    	virtual void execute() = 0;
    };
    
    // Implementation für non-member Funktion mit einem Argument
    template<typename ResultType, typename ArgumentType>
    struct CommandNM1 : Command
    {
    	typedef ResultType( *FuncPtr)( ArgumentType );
    
    	ResultType 				Result;
    	ArgumentType 			Argument;
    	FuncPtr					Function;
    
    	CommandNM1( FuncPtr Func, ArgumentType Arg ) :
    		Function( Func ),
    		Argument( Arg ),
    		Result( ResultType() )
    	{
    	}
    
    	virtual void execute()
    	{
    		Result = Function( Argument );
    	}
    };
    
    // Spezialisierung für non-member Funktionen mit einem Argument und ohne Rückgabewert
    template<typename ArgumentType>
    struct CommandNM1<void,ArgumentType> : Command
    {
    	typedef void( *FuncPtr)( ArgumentType );
    
    	ArgumentType 			Argument;
    	FuncPtr					Function;
    
    	CommandNM1( FuncPtr Func, ArgumentType Arg ) :
    		Function( Func ),
    		Argument( Arg )
    	{
    	}
    
    	virtual void execute()
    	{
    		Function( Argument );
    	}
    };
    
    template<typename ResultType, typename ArgumentType>
    Command* make_command( ResultType (*Func)( ArgumentType ), ArgumentType Arg )
    {
    	return new CommandNM1<ResultType,ArgumentType>( Func, Arg );
    }
    
    // Implementation für member Funktion mit einem Argument
    template<typename ObjectType, typename ResultType, typename ArgumentType>
    struct CommandM1 : Command
    {
    	typedef ResultType( ObjectType::*FuncPtr)( ArgumentType );
    
    	ResultType 				Result;
    	ArgumentType 			Argument;
    	FuncPtr					Function;
    	ObjectType&				Object;
    
    	CommandM1( ObjectType& Obj, FuncPtr Func, ArgumentType Arg ) :
    		Function( Func ),
    		Object( Obj ),
    		Argument( Arg ),
    		Result( ResultType() )
    	{
    	}
    
    	virtual void execute()
    	{
    		Result = (Object.*Function)( Argument );
    	}
    };
    
    template<typename ObjectType, typename ResultType, typename ArgumentType>
    Command* make_command( ObjectType& Obj, ResultType (ObjectType::*Func)( ArgumentType ), ArgumentType Arg )
    {
    	return new CommandM1<ObjectType,ResultType,ArgumentType>( Obj, Func, Arg );
    }
    
    void x( double y )
    {
    	int z = 0;
    }
    
    int f( double x )
    {
    	return x;
    }
    
    struct t
    {
    	int f( double x )
    	{
    		return x;
    	}
    };
    
    int main()
    {
    	t theT;
    	Command* c1 = make_command( f, 101.101 );
    	Command* c2 = make_command( theT, &t::f, 101.101 );
    	Command* c3 = make_command( x, 101.101 );
    
    	(*c1)();
    	(*c2)();
    	(*c3)();
    }
    

    Hab mal was (nur so aus der Hüfte geschossen) gebastelt, was du benutzen könntest. Statt roher Zeiger wären smart pointer toll, eventuell kann man mit boost/TR1::function das noch schöner machen. Aber als Hinweis taugt´s allemal was.

    vielen dank docshoe....ich versuch mich da mal durchzuarbeiten. mit templates hab ich noch eher wenig erfahrung.



  • Zeile 32:

    Result( ResultType() )

    was passiert hier???



  • pat.de schrieb:

    Zeile 32:

    Result( ResultType() )

    was passiert hier???

    Es wird die Member Variable Result mit dem Default-Konstruierten Wert von ResultType initialisiert.



  • theta schrieb:

    pat.de schrieb:

    Zeile 32:

    Result( ResultType() )

    was passiert hier???

    Es wird die Member Variable Result mit dem Default-Konstruierten Wert von ResultType initialisiert.

    vielen dank....habe es einfach mal mit int getestet.

    zeile 44:

    struct CommandNM1<void,ArgumentType> : Command

    ist mir auch nicht so ganz klar geworden...



  • Die Spezialisierung ist notwendig, weil das generische CommandNM1 Template eine Membervariable vom Typ ReturnType anlegt (siehe Z. 25). Wenn die aufzurufende Funktion keinen Rückgabewert hat (also void), dann würde ReturnType durch void ersetzt. Der Standard verbietet allerdings Variablen vom Typ void , und das verhindert die Spezialisierung.

    Edit:
    Zeilennummer korrigiert



  • Vielen Dank nochmal....

    Jetzt habe ich das Problem, das ich den operator() mit evtl. rückgabewert und einem parameter aufrufen will.

    Command* c1 = make_command( set_startaddress, "set_startaddress" ); 
    (*c1)(400);
    

    hab dazu erstmal versucht am Code-Abschnitt "Implementation für non-member Funktion mit einem Argument" zu fummeln:

    // Implementation für non-member Funktion mit einem Argument
    template<typename ResultType, typename ArgumentType, typename IdType>
    struct CommandNM1 : Command<ResultType, ArgumentType>
    {
        typedef ResultType( *FuncPtr)( ArgumentType );
    
        ResultType					Result;
        IdType						Id;
        FuncPtr						Function;
    
        CommandNM1( FuncPtr Func, IdType _id ) :
            Function( Func ),
            Id( _id ),
    
        {
        }
    
    	virtual ResultType execute(ArgumentType Arg)
        {
    
    		return Function(Arg);
        }
    
    };
    

    hab dann anschließend die Basisklasse erweitert:

    // Abstrakte Basisklasse für alle möglichen Commands
    template<typename ResultType, typename ArgumentType>
    class Command
    {
    public:
        virtual ~Command()
        {
        }
    
        virtual ResultType operator()( ArgumentType _Arg)
        {
           return execute(_Arg);
        }
    
    private:
    	virtual ResultType execute(ArgumentType Arg) = 0;
    
    };
    

    und das Funktionstemplate dementsprechend verändert:

    template<typename ResultType, typename ArgumentType, typename IdType>
    Command<ResultType, ArgumentType>* make_command( ResultType (*Func)( ArgumentType ), IdType _Id )
    {
        return new CommandNM1<ResultType,ArgumentType, IdType>( Func, _Id);
    }
    

    Beim Kompilieren kommt dann folgender Fehler:
    Fehler 1 error C2955: "Command": Für die Verwendung der template-Klasse ist eine template-Argumentliste erforderlich.
    Fehler 2 error C2440: 'Initialisierung': 'Command<ResultType,ArgumentType> *' kann nicht in 'Command *' konvertiert werden
    Fehler 3 error C3848: Ausdruck mit Typ 'Command' verliert beim Aufrufen von 'ResultType Command<ResultType,ArgumentType>::operator ()(ArgumentType)' möglicherweise einige const-volatile-Qualifizierer

    Weiss leider nicht mehr weiter und wäre über eure Hilfe sehr dankbar...



  • Command ist kein Typ, sondern ein Template. Für einen gültigen Typen musst du die Template-Argumente angeben.

    Abgesehen davon sind Bezeichner wie _Arg oder _Id , die mit Unterstrich und Grossbuchstaben beginnen, für die Implementierung reserviert. Du solltest sie nicht benutzen.



  • Die execute() Methode habe ich absichtlich ohne Rückgabewert und Parameter implementiert, dafür ist sie ja virtuell. Wenn du Parameter oder Rückgabewerte brauchst werden die als Member des konkreten Command Typen realisiert. Vereinfacht sieht das dann so aus:

    struct Command
    {
       int Result;
       double Argument;
       FuncPtr Func; 
    
       void execute()
       {
          Result = (*FuncPtr)( Argument );
       }
    };
    
    int main()
    {
       Command c;
    
       c.Argument = 101.101;
       c.execute();
       int Ergebnis = c.Result;
    }
    

    Die verschiedenen Ableitungen von Command garantieren, dass ich Command als Basisklasse verwenden darf. Dazu gehört leider auch, dass Command eine Signatur haben muss, über das es alle möglichen Funktionen aufrufen kann, und das ist nun mal void execute() . Die Behandlung von Rückgabewerten oder Aufrufparametern muss irgendwie durch die entsprechenden abgeleiteten Klassen durchgeführt werden, deshalb haben hat CommandNM1 die Elemente Result und Argument .



  • Ich hab jetzt das Problem,dass ich über den Basisklassenzeiger nicht die Attribute der Objekte aus den abgeleiteten Klassen ändern kann. Wie löse ich das Problem am besten?

    Zusätzlich will ich noch Funktionen ohne Rückgabewert und Argumente übergeben, habe dazu den Quelltext wie folg erweitert:

    template<>
    struct CommandNM1<void,void> : Command
    {
        typedef void( *FuncPtr)( void );
    
    	string					   Id;
        FuncPtr                    Function;
    
        CommandNM1( FuncPtr Func, string Id_c ) :
    		Id(Id_c),
            Function( Func )
        {
        }
    
        virtual void execute(const int& arg)
        {
            Function(  );
        }
    
    	virtual void execute()
        {
            Function();
        }
    
    	virtual string getId()
        {
            return Id;
        }
    
    };
    

    und die Funktion Command make_command( ResultType (Func)( ArgumentType ), ArgumentType Arg, string Id )

    überladen:

    template<typename ResultType, typename ArgumentType>
    Command* make_command( ResultType (*Func)( ArgumentType ), string Id )
    {
        return new CommandNM1<ResultType,ArgumentType>( Func, Id );
    }
    

    wenn ich jetzt

    void test(void ){std::cout<<"hallo"; }
    
    int main()
    {
    
    	Flash flash52401;
    	int t=12;
    	flash_init_52401(flash52401);
    
    	Command* c1 = make_command(test ,"hallo");  ...
    

    aufrufe sagt der compiler:
    Fehler 1 error C2780: 'Command *make_command(ObjectType &,ResultType (__thiscall ObjectType::* )(ArgumentType),ArgumentType,std::string)': Erwartet 4 Argumente - 2 unterstützt
    Fehler 4 error C2780: 'Command *make_command(ResultType (__cdecl *)(ArgumentType),ArgumentType,std::string)': Erwartet 3 Argumente - 2 unterstützt
    Fehler 2 error C2784: "Command *make_command(ResultType (__cdecl *)(ArgumentType),std::string)": template-Argument für "überladener Funktionstyp" konnte nicht von "überladener Funktionstyp" hergeleitet werden.
    Fehler 3 error C2784: "Command *make_command(ResultType (__cdecl *)(ArgumentType),std::string)": template-Argument für "überladener Funktionstyp" konnte nicht von "überladener Funktionstyp" hergeleitet werden.

    bin am verzweifeln....



  • Funktionsaufrufe ohne Argument sind eine neue Template Klasse, die du mit den bisherigen Templates nicht abdecken kannst. Wenn du member und non-member Funktionen damit erschlagen willst brauchst du 4 neue Template Klassen (jeweils 2 für non-member und 2 für member Funktionen, wegen der void Spezialisierung). Wenn du aus denen allerdings auch noch die Rückgabewerte auslesen willst ufert das Ganze extrem aus.
    Um das zu vereinfachen könnte man die Basisklasse mit einem Variant Datentyp ausstatten, der den Rückgabewert eines Commands aufnimmt. Damit geht zwar die Typsicherheit flöten, aber man muss keine halsbrecherischen Konstrukte bauen, um an das Ergebnis eines Funktionsaufrufs zu kommen. Du brauchst zwar immer noch 4 templates für jede Kombination einer Funktion (void/non-void und member/non-member), bist damit aber dann auch fertig.



  • vielen dank... hab den quellcode jetzt erweitert(für (member-funktion ohne rückgabe und argument) und für( non member ohne rückgabe und ohne argument) ).

    Jetzt habe ich folgendes Problem: Ich habe auch Funktionen mit Verweise bspw.

    void set_startaddress(const int &addr)
    

    ...muss ich dafür auch wieder extra eine template-kalsse erstellen??



  • Ich würde den Übergabeparameter von const int& auf int ändern, intrinsische Datentypen per const reference zu übergeben macht wenig Sinn, die kannst du besser per value übergeben. Dann brauchst du auch kein neues Template.



  • Ich würde den Übergabeparameter von const int& auf int ändern, intrinsische Datentypen per const reference zu übergeben macht wenig Sinn, die kannst du besser per value übergeben. Dann brauchst du auch kein neues Template.

    habe ich jetzt so gemacht... aber wieso macht das wenig Sinn und was versteht man unter intrinsische Datentypen(Datentypen wie int, char usw. die zum Standart gehören, also integrierte?)? per reference wird doch nciht extra eine kopie des Objekts erstellt, ist das nicht leistungsschonender?

    Jetzt ist mal wieder ein ganz anderes Problem aufgetreten... ich habe gestern auf die klasse fertig geschrieben, meine command objekt erstellt und alles lief. jetzt habe ich das projekt in visual studio 2010 eingefügt(vorher vs2008) und der compiler gibt mir den fehler:

    Fehler 1 error LNK2005: "class Command * __cdecl make_command(void (__cdecl*)(void),class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?make_command@@YAPAVCommand@@P6AXXZV?basic_string@DU?basic\_string@DU?char_traits@D@std@@V?$allocator@D@2@@std@@@Z) ist bereits in command.obj definiert. c:\Users\administrator\documents\visual studio 2010\Projects\server-software\Server-Software\main.obj
    Fehler 2 error LNK1169: Mindestens ein mehrfach definiertes Symbol gefunden. c:\users\administrator\documents\visual studio 2010\Projects\server-software\Debug\Server-Software.exe 1

    aus...wodran könnte das liegen??? ist doch der gleiche quellcode?

    Hier mein code aus der class command:

    #include <string>
    #include "string.h"
    using namespace std;
    // Abstrakte Basisklasse für alle möglichen Commands
    class Command
    {
    public:
    
        virtual ~Command()
        {
        }
    
    	void operator()(const int& arg)
        {
            execute(arg);
        }
    
    	void operator()()
        {
            execute();
        }
    
    	bool operator==( string Id)
        {
    		if(Id.compare(this->getId()))
    			return false;
    		else
    			return true;
        }
    
    private:
    
    	virtual void execute(const int& arg) = 0;
    	virtual void execute() = 0;
    
    	virtual string getId() = 0;
    
    };
    
    // Implementation für non-member Funktion mit einem Argument und Rückgabewert
    template<typename ResultType, typename ArgumentType>
    struct CommandNM1 : Command
    {
        typedef ResultType( *FuncPtr)( ArgumentType );
    
    	string					   Id;
        ResultType                 Result;
        ArgumentType			   Argument;
        FuncPtr                    Function;
    
        CommandNM1( FuncPtr Func, ArgumentType Arg, string Id_c ) :
    		Id(Id_c),
            Function( Func ),
            Argument( Arg ),
            Result( ResultType() )
        {
        }
    
    	virtual void execute()
        {
            Result = Function(Argument);
        }
    
    	virtual string getId()
        {
            return Id;
        }
    };
    
    // Spezialisierung für non-member Funktionen mit einem Argument und ohne Rückgabewert
    template<typename ArgumentType>
    struct CommandNM1<void,ArgumentType> : Command
    {
        typedef void( *FuncPtr)( ArgumentType );
    
    	string					   Id;
        ArgumentType			   Argument;
        FuncPtr                    Function;
    
        CommandNM1( FuncPtr Func, ArgumentType Arg, string Id_c ) :
    		Id(Id_c),
            Function( Func ),
            Argument( Arg )
        {
        }
    
    	virtual void execute(const int& arg)
        {
            Function(arg);
        }
    
    	virtual void execute()
        {
            Function(Argument);
        }
    
    	virtual string getId()
        {
            return Id;
        }
    
    };
    
    template<typename ResultType, typename ArgumentType>
    Command* make_command( ResultType (*Func)( ArgumentType ), ArgumentType Arg, string Id )
    {
        return new CommandNM1<ResultType,ArgumentType>( Func, Arg, Id );
    }
    
    //Implementation für Non-Member Funktionen ohne Rückgabewert und Argument
    struct CommandNM1V : Command
    {
        typedef void( *FuncPtr)( void );
    
    	string					   Id;
        FuncPtr                    Function;
    
        CommandNM1V( FuncPtr Func,  string Id_c ) :
    		Id(Id_c),
            Function( Func )
        {
        }
    
    	virtual void execute(const int& arg)
        {
            Function();
        }
    
    	virtual void execute()
        {
            Function();
        }
    
    	virtual string getId()
        {
            return Id;
        }
    
    };
    
    Command* make_command( void (*Func)( void ), string Id )
    {
        return new CommandNM1V( Func, Id );
    }
    
    // Implementation für member Funktion mit einem Argument und Rückgabewert
    template<typename ObjectType, typename ResultType, typename ArgumentType>
    struct CommandM1 : Command
    {
        typedef ResultType( ObjectType::*FuncPtr)( ArgumentType );
    
    	string					   Id;
        ResultType                 Result;
        ArgumentType	           Argument;
        FuncPtr                    Function;
        ObjectType&                Object;
    
        CommandM1( ObjectType& Obj, FuncPtr Func, ArgumentType Arg, string Id_c ) :
    		Id(Id_c),
            Function( Func ),
            Object( Obj ),
            Argument( Arg ),
            Result( ResultType() )
        {
        }
    
        virtual void execute(const int& arg)
        {
            Result = (Object.*Function)( arg );
        }
    
    	virtual void execute()
        {
            Result = (Object.*Function)(Argument);
        }
    
    	virtual string getId()
        {
            return Id;
        }
    };
    
    // Implementation für member Funktion mit einem Argument und ohne Rückgabewert
    template<typename ObjectType, typename ArgumentType>
    struct CommandM1 <ObjectType ,void ,ArgumentType> : Command
    {
        typedef void( ObjectType::*FuncPtr)( ArgumentType );
    
    	string					   Id;
        ArgumentType               Argument;
        FuncPtr                    Function;
        ObjectType&                Object;
    
        CommandM1( ObjectType& Obj, FuncPtr Func, ArgumentType Arg, string Id_c ) :
    		Id(Id_c),
            Function( Func ),
            Object( Obj ),
            Argument( Arg )
        {
        }
    
        virtual void execute(const int& arg)
        {
            (Object.*Function)( arg );
        }
    
    	virtual void execute()
        {
            (Object.*Function)(Argument);
        }
    
    	virtual string getId()
        {
            return Id;
        }
    };
    
    template<typename ObjectType, typename ResultType, typename ArgumentType>
    Command* make_command( ObjectType& Obj, ResultType (ObjectType::*Func)( ArgumentType ), ArgumentType Arg, string Id )
    {
        return new CommandM1<ObjectType,ResultType,ArgumentType>( Obj, Func, Arg, Id );
    } 
    
    // Implementation für member Funktion mit keinem Argument und ohne Rückgabewert
    template<typename ObjectType>
    struct CommandM1V : Command
    {
        typedef void( ObjectType::*FuncPtr)( void );
    
    	string					   Id;
        FuncPtr                    Function;
        ObjectType&                Object;
    
        CommandM1V( ObjectType& Obj, FuncPtr Func,  string Id_c ) :
    		Id(Id_c),
            Function( Func ),
            Object( Obj )
        {
        }
    
    	virtual void execute(const int& arg)
        {
            (Object.*Function)(  );
        }
    
    	virtual void execute()
        {
            (Object.*Function)();
        }
    
    	virtual string getId()
        {
            return Id;
        }
    };
    
    template<typename ObjectType>
    Command* make_command( ObjectType& Obj, void (ObjectType::*Func)( void ), string Id )
    {
        return new CommandM1V<ObjectType>( Obj, Func,  Id );
    }
    


  • pat.de schrieb:

    per reference wird doch nciht extra eine kopie des Objekts erstellt, ist das nicht leistungsschonender?

    Die Referenz wird intern üblicherweise als Zeiger übergeben, welcher auf gängigen Systemen mindestens so viel Speicher wie int verbraucht. Außerdem kostet die Zeigerindirektion beim Zugriff zusätzlich.



  • pat.de schrieb:

    Jetzt ist mal wieder ein ganz anderes Problem aufgetreten... ich habe gestern auf die klasse fertig geschrieben, meine command objekt erstellt und alles lief. jetzt habe ich das projekt in visual studio 2010 eingefügt(vorher vs2008) und der compiler gibt mir den fehler:

    Fehler 1 error LNK2005: "class Command * __cdecl make_command(void (__cdecl*)(void),class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?make_command@@YAPAVCommand@@P6AXXZV?basic_string@DU?basic\_string@DU?char_traits@D@std@@V?$allocator@D@2@@std@@@Z) ist bereits in command.obj definiert. c:\Users\administrator\documents\visual studio 2010\Projects\server-software\Server-Software\main.obj
    Fehler 2 error LNK1169: Mindestens ein mehrfach definiertes Symbol gefunden. c:\users\administrator\documents\visual studio 2010\Projects\server-software\Debug\Server-Software.exe 1

    aus...wodran könnte das liegen??? ist doch der gleiche quellcode?

    Ist nicht der gleiche Quellcode, entweder nicht an der gleichen Stelle (Header/Source), oder du hattest den header vorher nur einmal eingebunden, oder make_command (die nicht-Template-Funktion) neu hinzugefügt.

    Dein Problem ist eines der üblichen für die Fehlermeldung: Du hast die ODR verletzt, indem du eine Funktion mit externer Linkage in mehreren Übersetzungseinheiten definiert hast.
    Externe Linkage haben alle Funktionen, die
    - nicht static sind
    - nicht in anonymen namespaces liegen
    - nicht inline sind

    In deinem Fall ist letzteres der Knackpunkt: du hast den header mit der Definition einer nicht-inline, nicht-template Funktion in zwei Übersetzungseinheiten eingebunden und damit in beiden ÜEs eine Definition dieser Funktion. Der Linker kann nicht erkennen, dass es die selbe Definition ist und er eine von beiden ignorieren könnte. Die Funktionstemplates sind von der ODR nicht betroffen, da nimmt der Linker einfach die erstbeste Instantiierung und geht stillschweigend davon aus, dass alle gleich sind.


Anmelden zum Antworten