Forum: PC-Programmierung oop und virtual


von Benny (Gast)


Lesenswert?

Hallo miteinander.
Ich versuche gerade in meinem Projekt (c++) virtuelle Basisklassen und 
virtuelle Funktionen zu implementieren.

Der Aufbau in .h erweist sich für mich als günstig. Die Klasse derived3 
leited derived1 u. derived2 ab, wobei base nur einmalig vorhanden ist.
Es soll in .cpp dann nur eine Instanz der Klasse derived3 geben.

Genau das ist aber mein Problem. Da ich auch virtuelle Funktionen nutzen 
möchte, die unter best. Umständen entweder func() aus derived1 oder eben 
func() aus derived2 aufruft, bekomme ich es nicht hin, nur mit einer 
Instanz d3(Zeiger auf derived3)
auszukommen.

Sobald ich ja eine Instanz auf derived1 od. 2 erzeuge, ist die 
Basisklasse ja wieder doppelt drin, was ich ja urspruenglich mit der 
virtuellen Basisklasse vermeiden wollte???
in .h:
-------------------------------------------
class base
{
     virtual void func();
}

class derived1: public virtual base
{
     void func();

}

class derived2: public virtual base
{
     void func();
}

class derived3: public derived1, public derived2
{
...
}
---------------------------------------------------
//das geht zwar so, ist aber nicht gewuenscht
in .cpp:
derived3 * d3 = new derived3;
derived2 * d2 = d3;//jetzt ist doch die Basisklasse 2 mal erzeugt
derived1 * d1 = d3;//und jetzt 3mal

test(base * pInst)
{
   pInst->func();
}
...
if(flag_d2)
(
    test(d2);
)
if(flag_d1)
{
    test(d1);
}

von Oliver S. (oliverso)


Lesenswert?

Dein Problem nennt sich Mehrfachvererbung bzw. "multiple inheritance", 
und hat mit virtuellen Basisklassen und virtuellen Funktionen erst 
einmal nichts zu tun.

In den allermeisten Fällen ist Mehrfachvererbung nicht erforderlich, und 
Zeichen für ein unglückliches Design. Anfänger sollten es damit halten, 
wie mit goto: Ja, das gibt es, aber solange man nicht ganz genau weiß, 
was man tut, Finger weg. Es geht grundsätzlich und fast immer auch 
besser ohne.

Wenn es partout nicht ohne geht, guggst du z.B. hier:
http://www.paprots.com/red-inferno/cplusplus/basic/OOP/multi_inheritance/main.htm

Oliver

von Rolf M. (rmagnus)


Lesenswert?

Benny schrieb:
> Hallo miteinander.
> Ich versuche gerade in meinem Projekt (c++) virtuelle Basisklassen und
> virtuelle Funktionen zu implementieren.

Virtuelle Vererbung braucht man eigentlich sehr selten.

> Sobald ich ja eine Instanz auf derived1 od. 2 erzeuge, ist die
> Basisklasse ja wieder doppelt drin, was ich ja urspruenglich mit der
> virtuellen Basisklasse vermeiden wollte???

Du erzeugst doch gar keine Instanzen.

> //das geht zwar so, ist aber nicht gewuenscht
> in .cpp:
> derived3 * d3 = new derived3;
> derived2 * d2 = d3;//jetzt ist doch die Basisklasse 2 mal erzeugt

Nein, warum? Du kopierst einen Zeiger. Mehr nicht. Eine Instanz 
irgendeiner Klasse wird dabei nicht erzeugt.

> derived1 * d1 = d3;//und jetzt 3mal

Hier auch nicht.

Oliver S. schrieb:
> Dein Problem nennt sich Mehrfachvererbung bzw. "multiple inheritance",
> und hat mit virtuellen Basisklassen und virtuellen Funktionen erst
> einmal nichts zu tun.

Das Problem hat auch mit Mehrfachvererbung eigentlich nichts zu tun.

von Vlad T. (vlad_tepesch)


Lesenswert?

Existieren in der Vererbungshierarchie mehrere Member (daten oder 
Funktionen) mit gleichen namen, kann man diese aus der Klasse selbst 
explizit ansprechen. von außen reicht es das member in den 
entsprechenden Typ zu casten.


1
derived3::doSomething(){
2
  func();           // ruft eigene Implementierung auf
3
  derived2::func(); // ruft Implementierung aus derived2 auf
4
  base::func();     // ruft Implementierung von base auf
5
}

von außen geht das:
1
if(flag_d2)
2
(
3
    static_cast<derived2*>(d3)->func();
4
)
5
if(flag_d1)
6
{
7
    static_cast<derived1*>(d3)->func();
8
}

wenn sowas nötig sein sollte, scheint es aber, als wäre dein Design 
kaputt.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Vlad Tepesch schrieb:
> von außen geht das:
> if(flag_d2)
> (
>     static_cast<derived2*>(d3)->func();
> )
> if(flag_d1)
> {
>     static_cast<derived1*>(d3)->func();
> }

Nein, so funktioniert das nicht.
So würde es gehen:
1
if(flag_d2)
2
(
3
    d3->derived2::func();
4
)
5
if(flag_d1)
6
{
7
    d3->derived1::func();
8
}

von Oliver S. (oliverso)


Lesenswert?

Rolf Magnus schrieb:
> Das Problem hat auch mit Mehrfachvererbung eigentlich nichts zu tun.

Hm, eigentlich doch. Probleme macht das hier:
>class derived3: public derived1, public derived2
>{
>...
>}

wegen der Mehrfachvererbung. Das macht er vermutlich deshalb:

Benny schrieb:
> Da ich auch virtuelle Funktionen nutzen
> möchte, die unter best. Umständen entweder func() aus derived1 oder eben
> func() aus derived2 aufruft,

Und das wiederum ist schlicht kaputtes Design.

Oliver

von Oliver S. (oliverso)


Lesenswert?

1
class base
2
{
3
     virtual void func();
4
}
5
6
class derived1: public virtual base
7
{
8
     void func();
9
10
}
11
12
class derived2: public virtual base
13
{
14
     void func();
15
}

Soweit, so gut. Damit geht folgendes:
1
base *p;
2
base *b = new base;
3
derived1 *d1 = new derived1;
4
derived2 *d1 = new derived2;
5
6
p = b;
7
p->func(); // ruft base::func auf
8
p = d1;
9
p->func(); // ruft derived1::func auf
10
p = d2;
11
p->func(); // ruft derived2::func auf

Was nicht geht, ist aus einer Instanz von derived1 die Methode 
derived2::func aufzurufen. Die beiden "kennen" sich gar nicht.

Oliver

von Rolf M. (rmagnus)


Lesenswert?

Oliver S. schrieb:
> Rolf Magnus schrieb:
>> Das Problem hat auch mit Mehrfachvererbung eigentlich nichts zu tun.
>
> Hm, eigentlich doch. Probleme macht das hier:
>>class derived3: public derived1, public derived2
>>{
>>...
>>}
>
> wegen der Mehrfachvererbung.

Das Problem, das er hat, basiert darauf, daß er offenbar Zeiger noch 
nicht richtig verstanden hat, insbesondere im Zusammenhang mit 
Vererbung. Er glaubt, daß durch das Kopieren des Zeigers auf das Objekt 
auf einmal neue Instanzen der Basisklasse entstehen, was aber nicht der 
Fall ist:

Benny schrieb:
> derived3 * d3 = new derived3;
> derived2 * d2 = d3;//jetzt ist doch die Basisklasse 2 mal erzeugt
> derived1 * d1 = d3;//und jetzt 3mal

Oliver S. schrieb:
> Was nicht geht, ist aus einer Instanz von derived1 die Methode
> derived2::func aufzurufen. Die beiden "kennen" sich gar nicht.

Mit einem Cast könnte man das schon hinkriegen, aber es wäre natürlich 
überhaupt nicht sinnvoll, denn dann müßte derived1 ja annehmen, daß es 
nur als Teil von Klassen verwendet wird, die auch von derived2 
abgeleitet sind. Aber dann wäre es nicht mehr sinnvoll, derived1 und 
derived2 überhaupt zu getrennten Klassen zu machen.

von Karl H. (kbuchegg)


Lesenswert?

Wie weiter oben schon geschrieben, sollte man als allererstes mal diese 
ganze Diamond-Hierarchie in Frage stellen. Es wäre höchst ungewöhnlich, 
dass ein Neuling da drüber stolpert und das unbedingt benötigt.

von Bernd K. (prof7bit)


Lesenswert?

Rolf Magnus schrieb:

> Virtuelle Vererbung braucht man eigentlich sehr selten.

Braucht man eigentlich immer.

von Sven B. (scummos)


Lesenswert?

Bernd K. schrieb:
> Rolf Magnus schrieb:
>
>> Virtuelle Vererbung braucht man eigentlich sehr selten.
>
> Braucht man eigentlich immer.

Ja. Das braucht man eigentlich fast immer. Mehrfachvererbung ist ein 
bisschen subtil und nicht so oft sinnvoll (auch hier: was willst du 
eigentlich erreichen?), aber virtuelle Vererbung braucht man ständig.

von Rolf M. (rmagnus)


Lesenswert?

Sven B. schrieb:
> Bernd K. schrieb:
>> Rolf Magnus schrieb:
>>
>>> Virtuelle Vererbung braucht man eigentlich sehr selten.
>>
>> Braucht man eigentlich immer.
>
> Ja. Das braucht man eigentlich fast immer.

Ich habe es noch nie gebraucht.

> Mehrfachvererbung ist ein bisschen subtil und nicht so oft sinnvoll (auch
> hier: was willst du eigentlich erreichen?), aber virtuelle Vererbung
> braucht man ständig.

Die ergibt doch erst bei Mehrfachvererbung einen Sinn.

von Oliver (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Sven B. schrieb:
>> Bernd K. schrieb:
>>> Rolf Magnus schrieb:
>>>
>>>> Virtuelle Vererbung braucht man eigentlich sehr selten.
>>>
>>> Braucht man eigentlich immer.
>>
>> Ja. Das braucht man eigentlich fast immer.
>
> Ich habe es noch nie gebraucht.

Ich auch nicht. Gibts ja auch noch nicht so lange.

Nur geht es hier auch gar nicht darum. Der TO fängt gerade mal mit 
virtuellen Funktionen an. Die sind Basis-C++.

Oliver

von Sven B. (scummos)


Lesenswert?

Rolf Magnus schrieb:
> Die ergibt doch erst bei Mehrfachvererbung einen Sinn.
Ok, ok, "die andere" virtuelle Vererbung :-)
Die braucht man tatsächlich kaum.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.