Abstrakte Klassen



  • Hallo,

    ich wollte heute das Konzept von Interfaces in C++ mal nachbauen.

    Dafür wollte ich z.B. eine abstrakte Klasse IComparable erstellen, die 2 Methoden hat:

    class IComparable
    {
    public:
    	virtual bool Equals(IComparable& obj) const = 0;
    	virtual int CompareTo(IComparable& obj) const = 0;
    
    	/*virtual bool operator == (IComparable& obj) const;
    	virtual bool operator < (IComparable& obj) const;
    	virtual bool operator > (IComparable& obj) const;
    	virtual bool operator <=(IComparable& obj) const;
    	virtual bool operator >=(IComparable& obj) const;*/
    };
    

    Zum Kommentar komme ich gleich.

    So, ich habe nun eine Klasse, die IComparable erbt:

    class ABC : public IComparable
    {
    public:
    	virtual bool Equals(ABC& lawl) const
    	{
    		return this->a == lawl.a;
    	}
    
    	virtual int CompareTo(ABC& lawl) const
    	{
    		if (this->a < lawl.a)
    			return -1;
    		else if (this->a == lawl.a)
    			return 0;
    		else
    			return 1;
    	}
    	int a; // Nur zum Test
    };
    

    So, ich dachte eigentlich, dass das problemlos funktionieren würde, da ich die beiden abstrakten Methoden überschreibe. Aber, bei folgendem Code erhalte ich folgende Fehlermeldungen:

    ABC a;
    	a.a = 10;
    	ABC b;
    	b.a = 11;
    	if (a.Equals(b))
    		wcout << L"GLEICH" << endl;
    	else
    		wcout << b.CompareTo(a) << endl;
    
    1>.\main.cpp(31) : error C2259: 'ABC' : cannot instantiate abstract class
    1>        due to following members:
    1>        'bool IComparable::Equals(IComparable &) const' : is abstract
    1> .\IComparable.h(39) : see declaration of 'IComparable::Equals'
    1>        'int IComparable::CompareTo(IComparable &) const' : is abstract
    1> .\IComparable.h(40) : see declaration of 'IComparable::CompareTo'
    

    Woran liegt das, da ich die abstrakten Methoden ja eigentlich überschreibe?

    Nun zum Kommentar:
    Ich möchte, dass abgeleitete Klassen noch die Operator Überladungen optional bereit stellen können. Das heißt, sie KÖNNEN die Operatoren überladen, müssen es aber nicht. Kann ich das dann einfach so lassen, oder muss ich etwas beachten, oder, oder, oder... 😛

    Für Hilfe wäre ich dankbar.

    MfG
    plusman



  • plusman schrieb:

    Woran liegt das, da ich die abstrakten Methoden ja eigentlich überschreibe?

    Nein, tust du nicht: es gibt in C++ keine Parameter-Kovarianz.

    class ABC : public IComparable
    {
    public:
      //virtual bool Equals(ABC& lawl) const;
      virtual bool Equals(IComparable& lawl) const;
      //virtual int CompareTo(ABC& lawl) const;
      virtual int CompareTo(IComparable& lawl) const;
    };
    

    edit:
    Und überleg dir mal ob es unbedingt Sinn macht in C++ das Interface Comparable nachzubauen.
    Google Tip of the Day: Const-correctness



  • Hm, gut, das wäre dann gelöst.

    Nun will ich aber noch die Operatoren in der abstrakten Klasse überladen, da die abgeleiteten Klassen diese auch bereitstellen sollen.

    Die Operatoren sollen das gleiche Verhalten in jeder Klasse zeichen.

    Beispiel:

    bool IComparable::operator <  (const IComparable& obj) const
    {
    	return CompareTo(obj) < 0;
    }
    

    Der Operator selbst ist nicht als abstrakte "Methode" deklariert, also

    virtual bool operator <  (const IComparable& obj) const;
    

    Naja, das klappt so aber nicht. IComparable::CompareTo ist aber abstrakt, daher gibt es da wohl einen Fehler:

    1>main.obj : error LNK2001: unresolved external symbol "public: virtual bool __thiscall IComparable::operator<(class IComparable const &)const " (??MIComparable@@UBE_NABV01@@Z)
    

    Gibt es da eine Möglichkeit, das zum Umgehen, oder müsste jede abgeleitete Klasse die Operatoren selbst überladen und die Deklarationen verschwinden gänzlich aus IComparable?

    finix schrieb:

    Und überleg dir mal ob es unbedingt Sinn macht in C++ das Interface Comparable nachzubauen.

    Warum sollte es nicht sinnvoll sein? Vielleicht übersehe ich ja was 🙂

    MfG
    plusman



  • Nein das sollte funktionieren. Zeig mal den vonnständigen Code, ich nehm an das du da nur einen kleinen Denkfehler gemacht hast.

    grüße



  • Die Header:

    #pragma once
    
    class IComparable
    {
    public:
    	// Abstrakte Methoden, müssen überschrieben werden
    	virtual bool Equals(const IComparable& obj) const = 0;
    	virtual int CompareTo(const IComparable& obj) const = 0;
    
    	// Sollen von jeder Unterklasse automatisch verwendet werden können
    	virtual bool operator == (const IComparable& obj) const;
    	virtual bool operator <  (const IComparable& obj) const;
    	virtual bool operator >  (const IComparable& obj) const;
    	virtual bool operator <= (const IComparable& obj) const;
    	virtual bool operator >= (const IComparable& obj) const;
    };
    

    Die Cpp:

    #include "IComparable.h"
    
    bool IComparable::operator == (const IComparable& obj) const
    {
    	return Equals(obj);
    }
    
    bool IComparable::operator <  (const IComparable& obj) const
    {
    	return CompareTo(obj) < 0;
    }
    
    bool IComparable::operator >  (const IComparable& obj) const
    {
    	return CompareTo(obj) > 0;
    }
    
    bool IComparable::operator <= (const IComparable& obj) const
    {
    	return CompareTo(obj) <= 0;
    }
    
    bool IComparable::operator >= (const IComparable& obj) const
    {
    	return CompareTo(obj) >= 0;
    }
    

    Klasse ABC:

    class ABC : public IComparable
    {
    public:
    	virtual bool Equals(const IComparable& lawl) const
    	{
    		ABC& l = (ABC&)(lawl);
    		return this->a == l.a;
    	}
    
    	virtual int CompareTo(const IComparable& lawl) const
    	{
    		ABC& l = (ABC&)(lawl);
    		if (this->a < l.a)
    			return -1;
    		else if (this->a == l.a)
    			return 0;
    		else
    			return 1;
    	}
    	int a;
    };
    

    main.cpp:

    int main()
    {
    	ABC a;
    	a.a = 10;
    	ABC b;
    	b.a = 9;
    	if (a < b)
    		wcout << L"Kleiner" << endl;
    	return 0;
    }
    


  • Lässt sich compilieren... 🙂



  • Jup, der Fehler sitzt wie immer vor dem PC 🙂

    Das Zeug wird alles in eine DLL gepackt und ich hatte vergessen, die Klasse zu exportieren.

    Jetzt klappt es wunderbar.


Anmelden zum Antworten