COM Problem!



  • Hi,

    ich beschäftige mich momentan näher mit dem Component Object Model (COM), doch da bin ich beim coden auf ein problem gestoßen das ich selbst irgendwie nicht lösen kann!

    Hier erstmal der code:

    #include <iostream>
    
    // D E F I N I T I O N E N //////////////////////////////////////////////////////////
    typedef __int32 IID;
    
    const IID IID_IDirectGraphic	= 0x000000;
    const IID IID_IDirectGraphic2	= 0x000001;
    const IID IID_IDirectInputX		= 0x000002;
    
    // S T R U K T U R E N //////////////////////////////////////////////////////////////
    class IUnknown
    {
    public:
    	virtual __int32 __stdcall QueryInterface (const IID &iid, void **ppvObject) = 0;
    
    	virtual int __stdcall AddRef (void) = 0;
    	virtual int __stdcall Release (void) = 0;
    };
    
    class IDirectGraphic : public IUnknown
    {
    public:
    	virtual bool setMode (int value) = 0;
    };
    
    class IDirectGraphic2 : public IUnknown
    {
    public:
    	virtual bool setMode (int value) = 0;
    };
    
    class IDirectInputX : public IUnknown
    {
    public:
    	virtual bool getKey (int value) = 0;
    };
    
    class DirectIKS : public IDirectGraphic, public IDirectGraphic2, public IDirectInputX
    {
    public:
    	DirectIKS (void) : m_referenzZaehler(0) {}
    	virtual __int32 __stdcall QueryInterface (const IID &iid, void **ppbObject);
    	virtual int __stdcall AddRef (void);
    	virtual int __stdcall Release (void);
    
    	bool DirectGraphicCreate (IDirectGraphic **ppGI);
    	bool DirectInputXCreate (IDirectInputX **ppDI);
    
    		// WIE BEKOMME ICH DIESE BEIDEN FUNKTIONEN IN EINE CPP???????
    	virtual bool IDirectGraphic::setMode (int value) 
    	{ std::cout << "Interface IDirectGraphic wird benutzt!" << std::endl; return true; }
    	virtual bool IDirectGraphic2::setMode (int value) 
    	{ std::cout << "Interface IDirectGraphic2 wird benutzt!" << std::endl; return true; }
    
    	virtual bool getKey (int value);
    
    private:
    	int m_referenzZaehler;
    };
    
    __int32 __stdcall DirectIKS::QueryInterface (const IID &iid, void** ppvObject)
    {
    	switch (iid)
    	{
    	case IID_IDirectGraphic:
    		*ppvObject = (IDirectGraphic*)this;
    		break;
    	case IID_IDirectGraphic2:
    		*ppvObject = (IDirectGraphic2*)this;
    		break;
    	case IID_IDirectInputX:
    		*ppvObject = (IDirectInputX*)this;
    		break;
    	}
    
    	((IUnknown*)(*ppvObject))->AddRef();
    
    	return 0;
    }
    
    int __stdcall DirectIKS::AddRef (void)
    {
    	m_referenzZaehler++;
    	return m_referenzZaehler;
    }
    
    int __stdcall DirectIKS::Release (void)
    {
    	m_referenzZaehler--;
    
    	std::cout << m_referenzZaehler << std::endl;
    
    	if (m_referenzZaehler == 0)
    	{
    		delete this;
    		std::cout << "delete" << std::endl;
    		return 0;
    	}
    	else
    		return m_referenzZaehler;
    
    }
    
    bool DirectGraphicCreate (IDirectGraphic **ppDG)
    {
    	*ppDG = (IDirectGraphic*)new(DirectIKS);
    	if (!*ppDG)
    		return false;
    
    	((IUnknown*)(*ppDG))->AddRef ();
    
    	std::cout << "new" << std::endl;
    
    	return true;
    }
    
    bool DirectInputXCreate (IDirectInputX **ppDI)
    {
    	*ppDI = (IDirectInputX*)new(DirectIKS);
    	if (!*ppDI)
    		return false;
    
    	std::cout << "new" << std::endl;
    	((IUnknown*)(*ppDI))->AddRef ();
    
    	return true;
    }
    
    /*
    	// Normale implementierung einer setMode funktion, aber wie kann ich hier
    	// unterscheiden ob ich IDirectGraphic oder IDirectGraphic2 benutze wie
    	// oben in der Klasse unterschieden wird??????? geht das überhaupt???
    bool DirectIKS::setMode (int value)
    {
    	std::cout << "interface1" << std::endl;
    	return true;
    }
    */
    
    bool DirectIKS::getKey (int value)
    {
    	return true;
    }
    
    // M A I N //////////////////////////////////////////////////////////////////////////
    int main (void)
    {
    	IDirectGraphic	*pDG	= NULL;
    	IDirectGraphic2	*pDG2	= NULL;
    	IDirectInputX	*pDI	= NULL;
    
    	DirectGraphicCreate (&pDG);
    	DirectInputXCreate (&pDI);
    
    		// Interface Typ 2 abfragen
    	int x = pDG->QueryInterface (IID_IDirectGraphic2, (void**)&pDG2);
    
    		// Interface des Typs 1 benutzen
    	pDG->setMode (0);
    
    	if (pDG)
    		pDG->Release ();
    
    	pDI->getKey (0);
    
    		// Interface des Typs 2 benutzen
    	pDG2->setMode (0);
    
    	if (pDG2)
    		pDG2->Release ();
    
    	if (pDI)
    		pDI->Release ();
    
    	std::cin >> x;
    
    	return 0;
    }
    

    Ich möchte die Funktionen setMode() in der Cpp so unterscheiden wie in der klasse zu welchem Interface sie gehören! In der klasse klappt das Prima, doch in der CPP kannste das vergessen! ich hab schon alles ausprobiert und mit meinem Latein weiß ich bald net mehr weiter 😞

    Wie kann ich die Funktionen in der Cpp so gut unterscheiden wie in der Klasse DirectIKS?



  • *push*

    sorry das ich pushe aber das ist echt wichtig!



  • Wie wärs wenn du dann in eins der dafür vorgesehenen Foren postest. Ich sehe nicht den Zusammenhang zwischen COM und Standard C++. Wenns doch nur ein Problem mit der Sprache ist wär es hilfreich wenn du dein Posting auf das wesentliche beschränken würdest. Du kannst doch keinem zumuten solch einen ellenlangen Code mit irgendwelche DirectX-Sachen drin zu lesen. Deswegen lässt bestimmt auch die Antwort so lange auf sich warten



  • Hi,

    1. Wo ist da WinAPI oder DirectX????? Nirgends........
    2. Es geht um Standard C++! Nämlich wie man eine Funktion in eine CPP bekommt bei dem Aufbau
    3. COM kann man auf dem Standard anwenden bzw. COM ist nur ein Konzept und hat nix mit DX zu tun
    4. Wenn ich den code verkürze kapiert wieder keiner Worums geht! Weil der Aufbau dann fehlt!
    5. Nebenbei sind die Sachen die ich wissen will sehr gut Markiert im Quellcode

    und nun guck dir den code mal bitte an, denn es geht NUR um Standard C++



  • Verstehe das Problem nicht:

    bool IDirectGraphic::setMode (int value) 
        { std::cout << "Interface IDirectGraphic wird benutzt!" << std::endl; return true; }
        bool IDirectGraphic2::setMode (int value) 
        { std::cout << "Interface IDirectGraphic2 wird benutzt!" << std::endl; return true; }
    

    Das so in die cpp und in der .h

    class  IDirectGraphic 
    {
      //...
       virtual bool setMode (int value);
    };
    
    class  IDirectGraphic2
    {
      //...
       virtual bool setMode (int value);
    };
    

    btw wieso virtual blaaa() = 0 und dann ne definition für ?!



  • weil ich mich strickt an die MS-COM-Spezifikationen gehalten habe aus der MSDN



  • Hallo,
    1. ist das

    virtual bool IDirectGraphic::setMode (int value)
        { std::cout << "Interface IDirectGraphic wird benutzt!" << std::endl; return true; }
        virtual bool IDirectGraphic2::setMode (int value)
        { std::cout << "Interface IDirectGraphic2 wird benutzt!" << std::endl; return true; }
    

    mal kein Standard-C++. Die qualifizierten Namen IDirectGraphic::setMode bzw. IDirectGraphic2::setMode sind im Class-Scope nicht erlaubt. Nur im Namespace-Scope.

    Zu deinem Problem:
    Wenn ich dich richtig verstehe, ist das deine Situation (COM-befreit):

    class A
    {
    public:
        virtual void func();
    };
    
    class B
    {
    public:
        virtual void func();
    };
    
    class C : public A, public B
    {
    public:
        void func();
    };
    

    Du hast also zwei Klassen A und B die jeweils eine virtuelle Funktion mit dem *selben* Namen definieren und eine Klasse C, die von A und B erbt und die virtuelle Funktion überschreiben soll.
    Gleichzeitig soll die Funktionalität der virtuellen Funktion aber abhängig vom Interface sein. Sprich:

    C c;
    A* pA = &c;
    pA->func(); // soll A::func aufrufen
    B* pB = &c;
    pB->func(); // soll B::func aufrufen
    c.func();   // soll C::func aufrufen
    

    Die schlechte Nachricht: Das geht nicht. C::func überschreibt *beide* virtuellen Funktionen, wird hier also immer aufgerufen. Du hast danach *keine* Möglichkeit mehr, die beiden zu unterscheiden. Sprich: Du kannst in C::func *nicht* herausfinden, ob du über ein A-Interfac, B-Interface oder C-Interface aufgerufen wurdest.

    Es gibt jetzt zwei mögliche Lösungen:
    1. Wenn du func nicht über C aufrufen musst und du kein spezielles Verhalten in der am weitesten abgeleiteten Klasse brauchst, dann kannst du einfach auf das Überschreiben in C verzichten. Der Aufruf ist dann nur noch über das A-Interface oder das B-Interface möglich:

    int main() 
    {
    	C c;
    	A* pA = &c;	// OK: A::func
    	pA->func();
    	B* pB = &c;
    	pB->func();	// OK: B::fun
    	c.func();	// FEHLER! Mehrdeutig
    }
    

    2. Falls du wirklich eine Überschreibung in C brauchst, bleibt dir nichts anderes übrig, als die "Siamesichen Zwillinge" zu trennen.
    Das Problem ist klar: Zwei Funktionen haben den gleichen Namen. Lösung: Ändere den Namen. Und zwar per Vererbung.
    Zur Klasse A baust du eine abgeleitet Klasse AI, die der virtuellen Funktion einen neuen Namen gibt und zur alten Funktion forwarded:

    class AI : public A
    {
    public:
    	virtual void Afunc() = 0;
    private:
    	void func()	// überschreibt A::Func...
    	{
    		Afunc();	// und forwarded zu unserer neuen Funktion
    	}
    };
    

    Für B genauso:

    class BI : public B
    {
    public:
    	virtual void Bfunc() = 0;
    private:
    	void func()	// überschreibt B::Func...
    	{
    		Bfunc();	// und forwarded zu unserer neuen Funktion
    	}
    };
    

    C erbt nun statt von A und B von AI und BI. Hier überschreibst du nicht mehr func sondern Afunc und Bfunc:

    class C : public AI, public BI
    {
    public:
        void Afunc()
    	{
    		cout << "C als A" << endl;
    	}
    	void Bfunc()
    	{
    		cout << "C als B" << endl;
    	}
    };
    

    In eine cpp-Datei packst du das natürlich wie gewohnt:

    // c.h
    class C : public AI, public BI
    {
    public:
        void Afunc();
        void Bfunc();
    };
    
    // c.cpp
    void C::Afunc() {...}
    
    void C::Bfunc() {...}
    

    PS:: Sollten A oder B viele und komplizierte Konstruktoren besitzen, dann bietet es sich an AI und BI jeweils virtuell erben zu lassen. Damit ersparst du dir die Duplizierung des Ctor-Codes in AI bzw. BI.


Anmelden zum Antworten