Mehrfachvererbung und der Streit um die Familienjuwelen :-)

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Mehrfachvererbung und der Streit um die Familienjuwelen :-)

Beitrag von Xin » Mi Feb 13, 2013 3:13 pm

Gelegentlich muss ich auch noch ein kleines Testprogramm schreiben, nur um sicher zu gehen, dass ich meine Probleme richtig löse.
Das Problem ist nicht alltäglich, entsprechend schon was ausgefallener.
Wer Interesse hat, darf mein Problem nochmals lösen:

Code: Alles auswählen

#include <stdio.h>

class Base
{
    int Value;
public:
    Base( int value ) : Value(value) {}

    int getValue() { return Value; }
};

class Left : public Base
{
public:
    Left( int value ) : Base( value ) {}
};

class Right : public Base
{
public:
    Right( int value ) : Base( value ) {}
};

class Derived : public Left, public Right
{
public:
    Derived( int value )
        : Left( value )
        , Right( value+1 )
    {}

    using Left::getValue;
};

int main( void )
{
    Derived d( 1 );

    printf( "%d\n", d.Left::getValue() );
    printf( "%d\n", d.Right::getValue() );
}
Wie man hier sieht, ignoriert VisualStudio zum einen das using left::getValue und zum anderen das Problem: Ich bekomme bei getValue() zwei unterschiedliche Werte raus. Left wie Right sind von Base abgeleitet und durch die Mehrfachvererbung gibt es nun zwei unterschiedliche Bases und entsprechend zwei unterschiedliche Values, die ja auch unterschiedlich sein könnten.

Was muss man tun, damit Derived von Left und Right abgeleitet wird, die zwar beides Bases sind, Derived aber nur eine Base besitzt?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: Mehrfachvererbung und der Streit um die Familienjuwelen

Beitrag von Glocke » Do Feb 14, 2013 10:02 am

Xin hat geschrieben:Wie man hier sieht, ignoriert VisualStudio zum einen das using left::getValue
Also bei mir macht das using Left::getValue auch keinen Unterschied (g++).
Xin hat geschrieben:Left wie Right sind von Base abgeleitet und durch die Mehrfachvererbung gibt es nun zwei unterschiedliche Bases und entsprechend zwei unterschiedliche Values, die ja auch unterschiedlich sein könnten.
Ich habe dein Beispiel mal modifizert und der Base-Klasse zusätzlich einen Setter gegeben (zum Testen).

Code: Alles auswählen

#include <stdio.h>

class Base {
    int Value;
    public:
        Base( int value ) : Value(value) {}

        int getValue() { return Value; }
        void setValue(int val) { Value = val; }
};

class Left : public Base {
    public:
        Left( int value ) : Base( value ) {}
};

class Right : public Base {
    public:
        Right( int value ) : Base( value ) {}
};

class Derived : public Left, public Right {
    public:
        Derived( int value )
            : Left(value)
            , Right(value)
        {}

        int getValue() {
            return Left::getValue();
        }
        void setValue(int val) {
            Left::setValue(val);
            Right::setValue(val);
        }
};

int main( void ) {
    Derived d( 1 );

    printf( "%d\n", d.getValue() );
    printf( "%d\n", d.Left::getValue() );
    printf( "%d\n", d.Right::getValue() );

    d.setValue(17);

    printf( "%d\n", d.getValue() );
    printf( "%d\n", d.Left::getValue() );
    printf( "%d\n", d.Right::getValue() );
}
Ich würde in Derived Getter und Setter so neu implementieren, dass Left und Right analog gesetzt werden.
Das blöde ist nur, dass das jetzt für eine Membervariable von Base ist. Für jedes Member dieses Prozedere wäre auch wieder doof ... :cry:

Mal schauen ob mir noch etwas einfällt :| Ich befürchte du wirst nicht drumrum kommen das für jedes Member zu implementieren. Immerhin bringt die Mehrfachvererbung hier ja Mehrdeutigkeiten mit sich. Du bist der einzige der weiß, was der Code leisten soll und welches (in dem Fall beide gleichmäßig) Member gemeint ist. Blöd ist nur, dass dabei Unmengen an Mehr-Code entstehen :cry:

LG Glocke
Xin hat geschrieben:Was muss man tun, damit Derived von Left und Right abgeleitet wird, die zwar beides Bases sind, Derived aber nur eine Base besitzt?
/EDIT: Gibt es ab C++11 nicht die Möglichkeit den this-Zeiger zu modifizieren? Kp ob man das verwenden kann, um die Base von Right auf die Base von Left zeigen zu lassen ... wobei sich das vielleicht als schwierig herausstellen könnte, da Left und Right ja immernoch autonome Member haben sollten - sonst wäre es ja ein "Klon" vom anderen :lol:

Ansonsten sehe ich für die "eine Base für Derived" keine Möglichkeit.. :? siehe Diamond-Problem :mrgreen:

/EDIT2: Ansonsten würde mir nur einfallen Derived Instanzen von Left und Right als Member zu geben und gemeinsame Methoden implementieren. Aber auch hier ist recht viel Redundanz da ..

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Mehrfachvererbung und der Streit um die Familienjuwelen

Beitrag von Xin » Do Feb 14, 2013 10:29 am

Glocke hat geschrieben:
Xin hat geschrieben:Wie man hier sieht, ignoriert VisualStudio zum einen das using left::getValue
Also bei mir macht das using Left::getValue auch keinen Unterschied (g++).
Erstaunlich, da muss ich mich nochmal ransetzen - das habe ich anders gelernt.
Glocke hat geschrieben:
Xin hat geschrieben:Left wie Right sind von Base abgeleitet und durch die Mehrfachvererbung gibt es nun zwei unterschiedliche Bases und entsprechend zwei unterschiedliche Values, die ja auch unterschiedlich sein könnten.
Ich habe dein Beispiel mal modifizert und der Base-Klasse zusätzlich einen Setter gegeben (zum Testen).
...
Ich würde in Derived Getter und Setter so neu implementieren, dass Left und Right analog gesetzt werden.
Das blöde ist nur, dass das jetzt für eine Membervariable von Base ist. Für jedes Member dieses Prozedere wäre auch wieder doof ... :cry:
Eine schicke Methode. Nehmen wir nun mal an, dass Value ein 10MB großer Datenklotz ist.
Da werden in dem Fall dann 20MB draus.
Glocke hat geschrieben:Mal schauen ob mir noch etwas einfällt :|
Daher die Frage.
Glocke hat geschrieben:
Xin hat geschrieben:Was muss man tun, damit Derived von Left und Right abgeleitet wird, die zwar beides Bases sind, Derived aber nur eine Base besitzt?
/EDIT: Gibt es ab C++11 nicht die Möglichkeit den this-Zeiger zu modifizieren?
Das Problem ist schon älter als C++11 - die Lösung auch. :-)
Glocke hat geschrieben:/EDIT2: Ansonsten würde mir nur einfallen Derived Instanzen von Left und Right als Member zu geben und gemeinsame Methoden implementieren. Aber auch hier ist recht viel Redundanz da ..
Redundanz sorgt für fehlerhafte Programme. Wollen wir nicht (-:
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: Mehrfachvererbung und der Streit um die Familienjuwelen

Beitrag von Glocke » Do Feb 14, 2013 10:43 am

Xin hat geschrieben:Eine schicke Methode. Nehmen wir nun mal an, dass Value ein 10MB großer Datenklotz ist.
Da werden in dem Fall dann 20MB draus.
Ja die ist absoluter Overkill - in jeder Hinsicht :D
Xin hat geschrieben:Das Problem ist schon älter als C++11
Oh ja ^^
Xin hat geschrieben:die Lösung auch. :-)
Ich kenne leider nur die mit der Redundanz :?
Xin hat geschrieben:Redundanz sorgt für fehlerhafte Programme. Wollen wir nicht (-:
Seh ich genauso. Nur: Wäre die Lösung "preiswert", dann wäre die Mehrfachvererbung doch nicht so umstritten, dass sie in anderen objektorientierten Sprachen weggelassen wurde ;)

Lirrec
Beiträge: 15
Registriert: Mo Feb 20, 2012 11:55 am

Re: Mehrfachvererbung und der Streit um die Familienjuwelen

Beitrag von Lirrec » Do Feb 14, 2013 3:05 pm

Code: Alles auswählen

#include <stdio.h>

class Base
{
    int Value;
public:
    Base( int value ) : Value(value) {}

    int getValue() { return Value; }
};

class Left : public virtual Base
{
public:
    Left( int value ) : Base( value ) {}
};

class Right : public virtual Base
{
public:
    Right( int value ) : Base( value ) {}
};

class Derived : public Left, public Right
{
public:
    Derived( int value )
        : Base( value )
	, Left( value+1 )
        , Right( value+2 )
    {}
};

int main( void )
{
    Derived d( 1 );

    printf( "%d\n", d.Left::getValue() );
    printf( "%d\n", d.Right::getValue() );
}
Ausgabe: Mit virtuellen Basisklassen scheint sich das Problem zumindest zum Teil umgehen zu lassen, genaueres kann ich aber auch nicht dazu sagen.

Im obigen Beispiel ist es dann nötig von Derived aus auch den Base(int) Konstruktor aufzurufen.
Die Werte die an Left() und Right() gehen, scheinen ebenfalls überschrieben zu werden ( evtl liegt das an der internen Reihenfolge der Konstruktor Aufrufe? )

Edit:
Msdn hat z.B. eine Erklärung dazu http://msdn.microsoft.com/en-us/library ... s.80).aspx
Edit2: falscher code gepastet :oops:

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Mehrfachvererbung und der Streit um die Familienjuwelen

Beitrag von Xin » Do Feb 14, 2013 3:36 pm

Lirrec hat geschrieben:Mit virtuellen Basisklassen scheint sich das Problem zumindest zum Teil umgehen zu lassen, genaueres kann ich aber auch nicht dazu sagen.
Richtig - und schade, dass Du da nix genaueres zu sagen kannst... ich habe das zuletzt benutzt, als ich es erklärt habe und gestern brauchte ich es halt im Reallife. Da ich es schon beschrieben hatte, kannte ich das Problem und die Lösung.
Lirrec hat geschrieben:Msdn hat z.B. eine Erklärung dazu http://msdn.microsoft.com/en-us/library ... s.80).aspx
Wozu in die Ferne schweifen, wenn das Gute liegt so nah. ^^

cpp:inheritance:diamond, cpp:inheritance:virtual
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Lirrec
Beiträge: 15
Registriert: Mo Feb 20, 2012 11:55 am

Re: Mehrfachvererbung und der Streit um die Familienjuwelen

Beitrag von Lirrec » Do Feb 14, 2013 3:41 pm

Xin hat geschrieben: Wozu in die Ferne schweifen, wenn das Gute liegt so nah. ^^
cpp:inheritance:diamond, cpp:inheritance:virtual
Die Nähe haben wir, jetzt brauchen wir nur noch die Suchmaschinenoptimierung ;)

Antworten