# Vererbung und Überladen von virtuellen Methoden (Polymorphie)



## RuFFnEcK (17. Januar 2006)

Hallo zusammen,

ich hab da mal ne Frage 

Vorab ist es überhaupt Möglich virtuelle (ob rein oder nicht) Methoden zu überladen?
Falls nicht dann klickt doch bitte direkt unten auf Antworten und schreibt "NEIN",
ohne das hier weiter zu lesen, weil alles darauf aufbaut 

Ist das Möglich:


```
class A
{
private:
 double Value;

public:
    virtual bool getValue() ;
    virtual double getValue() ;
    virtual int getValue() ;
    virtual CString getValue();
}

class B : public A
{
 virtual bool getValue();
}
//Implementierung....
class C : public A
{
virtual double getValue();
}
//Implementierung
class D : public A
{
virtual CString getValue();
}
//Das ganze dann folgendermaßen nutzen will:
map <CString, A*> meineMap;
```

Die Klassen B, C und D implementieren jeweils nur die für sich interessanten Methoden.
Wenn ich jetzt die map mit B, C oder D Objekt fütter, funktioniert dann der Aufruf der getVar() Methode?


----------



## deepthroat (17. Januar 2006)

Hi.



			
				RuFFnEcK hat gesagt.:
			
		

> Vorab ist es überhaupt Möglich virtuelle (ob rein oder nicht) Methoden zu überladen?


Ja, sicher. (rein virtuelle Methoden muß man schließlich überladen können, oder?!)



			
				RuFFnEcK hat gesagt.:
			
		

> Die Klassen B, C und D implementieren jeweils nur die für sich interessanten Methoden.
> Wenn ich jetzt die map mit B, C oder D Objekt fütter, funktioniert dann der Aufruf der getVar() Methode?


Du hast es doch sicherlich schon ausprobiert. Warum sagst du's uns nicht? (bzw. warum probierst du's nicht einfach aus?)

Gruß


----------



## RuFFnEcK (17. Januar 2006)

Das Projekt wo ich dran sitze isn bisle größer und auch n bisle komplizierter als das was ich hier gepostet hab und wie immer alles unter Zeitdruck...
Ich schreib grad an meiner Bachelor Thesis, darum der Zeitdruck^^
Jedenfalls denke ich nicht dass das funktioniert.

Überladen funktioniert, klar! Aber nur anhand der Parameter und 
nicht Anhand der Rückgabewerte...
Im Prinzip is es klar woher soll der Compiler auch wissen welche Methode er Aufrufen soll *g*
War mein Fehler, hätte ich ein bisle mehr drüber nachgedacht wärs klar geworden...
Das Prob ist z.B. kann ich trotz abstracter Klasse dennoch auf die Methoden via Scope Zugreifen, aber dann weiß der Compiler nicht welche Methode, wenn keien Parameter vorhanden sind...

Grüße RuFF


----------



## deepthroat (17. Januar 2006)

RuFFnEcK hat gesagt.:
			
		

> Das Prob ist z.B. kann ich trotz abstracter Klasse dennoch auf die Methoden via Scope Zugreifen, aber dann weiß der Compiler nicht welche Methode, wenn keien Parameter vorhanden sind...


Äh, war das 'ne Frage?

Gruß


----------



## RuFFnEcK (17. Januar 2006)

DIes war vielmehr eine Festelung dass es nicht geht, inklusive Begründung^^
Aber lasse mich immer gerne eines besseren Belehren!

Grüße


----------



## deepthroat (17. Januar 2006)

Ah, OK. Das hat mit Vererbung nichts zu tun; du kannst die Funktionen nicht so überladen - die Funktionen müssen sich entweder in Anzahl oder Typ der Parameter unterscheiden.

Dann markier doch auch das Thema als erledigt.

Gruß


----------



## RuFFnEcK (17. Januar 2006)

Das hat mit Vererbung in soweit was zu tun, 
dass ich dachte dass das dabei vielleicht geht^^
Wenn ich mehrere virtuelle Methoden (nicht rein, erzwingt ja definition durch jeden Erber) mit verschiedenen Rückgabeparametern deklariere und dann nur die entsprechenden Methoden in der jeweiligen Erber Klasse definiere...
Aber C** schiebt mir nen Riegel vor, da sich wie du schon sagtest 
die Methoden mindestens in Art oder Anzahl der Parameter unterscheiden müssen...

Könnte man nicht theoretisch mit Funktionspointern arbeiten?
Es geht darum dass die Klassen Variablen einer Heizungselektronik darstellen 
und diese auch mal Strings enthalten können oder ganze Arrays...
Ich wollte eine rückgabe Methode haben die je nachdem um welche variable es sich handelt, diese zurück liefert...

Aber passt schon werde halt mehrere Methoden schreiben und eine Abfragefunktion die mir sagte welche ich nehmen muss^^


----------



## jsendrow (18. Januar 2006)

Dies läßt sich sogar relativ leicht mit C++ realisieren. Die Rückgabewerte von virtuellen Methoden können sich durchaus unterscheiden, wenn sie selbst wiederum eine gemeinsame Basisklasse haben.

Im ersten Schritt kannst Du also deine Werte in eigene Klassen packen:


```
class wert {
	int mWert;
public:
	wert() { mWert = 1; }

	virtual int type() { return 1; }
};

class wert1 : public wert {
	char mWert1;
public:
	wert1() { mWert1 = '*'; }

	virtual int type() { return 2; }
};

class wert2 : public wert {
	char* mWert2;
public:
	wert2() { 
		mWert2 = new char[32];
		strcpy(mWert, "Test");
	}

	virtual int type() { return 3; }
};
```

Damit läßt sich dann eine Funktion überladen, die unterschiedliche Rückgabepara,eter hat:


```
class A {
	wert mWert;
public:

	virtual wert* getWert() { return &mWert; }
};


class B : public A {
	wert1 mWert1;
public:

	virtual wert1* getWert() { return &mWert1; }
};

class C : public A {
	wert2 mWert2;
public:

	virtual wert2* getWert() { return &mWert2; }
};
```



> Aber passt schon werde halt mehrere Methoden schreiben und eine Abfragefunktion die mir sagte welche ich nehmen muss



Ich kann mich irren, aber das hört sich stark nach eine Prozeduralen und nciht nach eine OOP-Lösung an, daher auch Deine Probleme. Du scheinst es so zu lösen, daß die Abfragefunktion abhängig von den Rückgabewerten sich unterschiedlich verhält. Das entspricht aber nicht unbedingt dem Gedanken hinter OOP. Besser ist es, wenn die Abfragefunktion immer gleich ist und das spezielle Verhalten jeweils in die Werte-Klassen implementiert wird. Das ist natürlich nur geraten.


----------



## FireFlow (18. Januar 2006)

jsendrow hat gesagt.:
			
		

> Die Rückgabewerte von virtuellen Methoden können sich durchaus unterscheiden, wenn sie selbst wiederum eine gemeinsame Basisklasse haben.



Das was du mit dem Satz meinst (der ist komisch formuliert) stimmt nicht. Wenn du eine Methode *überschreibst* *MUSS* sie den gleichen Rückgabetyp haben. Du kannst jediglich eine neue Methode mit selben bezeichner deklarieren wenn sie sich in Anzahl und/oder Typen der Übergabeparameter, oder in der "Constness" unterscheidet. Aber dann hat das mit Überschreiben nichts mehr zu tun, das ist dann überladen und die Funktion in der Kindklasse überdeckt die der Basisklasse.

Gruß


----------



## RuFFnEcK (18. Januar 2006)

Hallöchen,

danke jsendrow, das ist ein Ansatz den ich bisher noch nicht in Betracht gezogen hatte...
Ich hab morgen die Startpresentsation und jetzt wirft dein Posting meinen gesamten Ansatz um...
Jetzt grübel ich den halben Tag schon über den Klassen und wie ich das ganze am besten Umsetzen soll...
Hätte doch lieber mit Together arbeiten sollen, weil jetzt ne Ansatz änderung ne Menge änderungen in den Visio-Diagrammen mit sich zieht...



			
				jsendrow hat gesagt.:
			
		

> Ich kann mich irren, aber das hört sich stark nach eine Prozeduralen und nciht nach eine OOP-Lösung an, daher auch Deine Probleme. Du scheinst es so zu lösen, daß die Abfragefunktion abhängig von den Rückgabewerten sich unterschiedlich verhält. Das entspricht aber nicht unbedingt dem Gedanken hinter OOP. Besser ist es, wenn die Abfragefunktion immer gleich ist und das spezielle Verhalten jeweils in die Werte-Klassen implementiert wird. Das ist natürlich nur geraten.



Ich hab ja nicht genau beschrieben um was es hierbei geht, darum irrst du dich 
Ich versuche einen OOP Ansatz, nur dachte ich bisher, 
wenn ich die von verschiedenen Klassen erzeugten Variablen Objekte 
in einer map benutzen will, die mit Objekten der Mutter Klasse deklariert ist, 
um eben Objekt einer beliebigen Tochter-Klasse nutzen zu können,
ich auch nur die Methoden nutzen kann die die Mutter-Klasse bereit stellt...

Also ich poste mal hier den bisherigen Code der Header Datei:


```
class CVar
{
public:
	//Std. C´tor sollte nicht genutzt werden!
	CVar(void);
	CVar(CString VarName, AddrType AddrTypeOfVar, DWORD AddressOfVar);
	virtual ~CVar(void);

private:
	CString		m_sName;
	AddrType	m_eType;
	DWORD		m_dwAddress;
	double		m_dValue;
	short		m_nScaling;
	BYTE		m_aRawData[5];

public:

	//All get Methods:
	CString		getVarName(void)	{return m_sName;}
	AddrType	getAdrrType(void)	{return m_eType;}
	DWORD		getAdrr(void)		{return m_dwAddress;}	
	short		getScaling(void)	{return m_nScaling;}

	//All set Methods:
	void	setVarName(CString Name);
	void	setAdrrType(AddrType AdrrTypeOfVar);
	void	setAdrr(DWORD AddrOfVar);
	void	setValue(double Value);
	bool	setScaling(short Scaling);

	void	resetRawData(void);
	virtual double getValue(void);	//Standard implementierung durch Mutter Klasse, kann von Töchtern überschrieben werden.
	virtual CString getAllValuesAsString(void)	PURE;	
};
//-----------------------------------------------------------------------------------------
class CSimpleVar : public CVar
{
private:

public:
	CSimpleVar();
	CSimpleVar(CString VarName, AddrType AddrTypeOfVar, DWORD AddressOfVar)
		{ CVar(VarName, AddrTypeOfVar, AddressOfVar); }
		
		
	static int nNrOfRawDataArrayEntries;
	

	
};
//-----------------------------------------------------------------------------------------
class CProtectedVar : public CVar
{	
private:

public:
	CProtectedVar(CString VarName, AddrType AddrTypeOfVar, DWORD AddressOfVar)
		{ CVar(VarName, AddrTypeOfVar, AddressOfVar); }
		
	static int nNrOfRawDataArrayEntries;


	
};
//-----------------------------------------------------------------------------------------
class CProtectedCombinedVar : public CVar
{	
private:

public:
	CProtectedCombinedVar(CString VarName, AddrType AddrTypeOfVar, DWORD AddressOfVar)
		{ CVar(VarName, AddrTypeOfVar, AddressOfVar); }
		
	static int nNrOfRawDataArrayEntries;


};
```

Aber ich arbeite grads ein neues Konzept aus und werde die Ergebnisse heut Abend hier posten...
Also noch keine Stelungnahme zu dem Code hier bitte^^
Der wird heut Abend nicht mehr aktuell sein!


----------



## jsendrow (18. Januar 2006)

FireFlow hat gesagt.:
			
		

> Das was du mit dem Satz meinst (der ist komisch formuliert) stimmt nicht. Wenn du eine Methode *überschreibst* *MUSS* sie den gleichen Rückgabetyp haben. Du kannst jediglich eine neue Methode mit selben bezeichner deklarieren wenn sie sich in Anzahl und/oder Typen der Übergabeparameter, oder in der "Constness" unterscheidet. Aber dann hat das mit Überschreiben nichts mehr zu tun, das ist dann überladen und die Funktion in der Kindklasse überdeckt die der Basisklasse.
> 
> Gruß



Stimmt, ungünstig formuliert, aber schau mal hier:



> Covariant Returns. A long-standing C++ rule requires that a member function that overrides a virtual function must not only have the same signature but also the same return value as the base class member function. In the following code, for example, A::f and B::f both return a pointer to an object of class X.
> class X
> {};
> 
> ...


----------



## RuFFnEcK (18. Januar 2006)

Salut,

also ich werde es jetzt so machen:

hab ne *CValue *Klasse geschrieben die alle möglichen Werte aufnehmen kann.
Eine "*CValue* getValue(void)*" methode ist nicht mehr virtuell und für jede Tochter Klasse gleich, da jetzt nur noch dem Datentyp entsprechend in CValue geschrieben wird.
Werde aber erst morgen das ganze implementieren und jetzt die Präsentation vorbereiten 

Euch allen vielen Dank, aber werde dann morgen bzw. übermorgen darauf zurück kommen, weil ich das noch gar nicht richtig ausgearbeitet hab und der Vortrag Priorität hat...

Grüsse


----------



## jokey2 (18. Januar 2006)

Ich glaube, ich würde das so machen, daß ich eine Template-Klasse schriebe, die die map enthält, etwa so: 
	
	
	



```
template <class T> class T_CStringMap
   {
   private:
   	map <CString, T> localMap;
   public:
   	T GetValue(CString cstrKey);
   };
   
   template <class T, int i>
   T T_CStringMap<T>::GetValue(CString cstrKey)
   {
   	return localMap.find(cstrKey)->second;
   };
```
Die Variablendeklaration dann so: 
	
	
	



```
T_CStringMap<int> CIntClass;
   T_CStringMap<bool> CBoolClass;
   T_CStringMap<double> CDoubleClass;
 T_CStringMap<CString> CCStringClass;
```
Die anderen map-Funktionen müssen dann natürlich auch noch implementiert werden.


----------



## deepthroat (19. Januar 2006)

Hi.





			
				jokey2 hat gesagt.:
			
		

> Ich glaube, ich würde das so machen, daß ich eine Template-Klasse schriebe, die die map enthält, etwa so:
> 
> 
> 
> ...


Aber wo ist da der Unterschied (außer größerer Aufwand) zu
	
	
	



```
map<CString, int> str2int;
map<CString, bool> str2bool; 
map<CString, double> str2double;
...
```

Gruß


----------



## RuFFnEcK (20. Januar 2006)

Hallo zusammen,

es ist fast unmöglich einen guten Ansatz zur Abbildung der Problematik zu finden, ohne die Problematik zu kennen!
DIe Klassen Konstrukte stellen folgendes dar:

Es existiert ein Bus (Bussystem welches eine Kommunikationsschnittstelle darstellt für bestimmte Geräte...
An diesem Bussystem können mehrere Geräte hängen. 
Diese Geräte haben jeweils eine eindeutige Softwareversion, 
anhand der ich mir Variablen Listen generieren kann mit Hilfe von Linker-, LinkerTypen- und Symbolischen Listen (Diese Listen enthalten alle Informationen, wie Adresse im EEprom des Geräts, Datentyp, Variablen Name...)
Was ich vorher im Programm kennen muss ist die Menge aller in allen geräten vorkommenden Datentypen.

Mein Vorhaben:
EIne Klasse die die Geräte Abbildet : (CDevice)
Jeder Datentyp wird von einer bestimmten Klasse dargestellt.
Ich erzeuge dann einfach ein Objekt des entsprechenden Datentyps für jeweils eine Variable...
Jedes Device soll nur eine map haben die alle Variablen beinhaltet!
Naja hatte die letzten zwei Tage keine Zeit mehr dran zu arbeiten, aber werde jetzt weiter machen und Ergebnisse hier posten 

Grüße


----------

