5 Stimmen

Kopieren von Methoden aus Mitglied

Ich habe eine einfache, einfache Containerklasse, die von einer anspruchsvolleren Dateiklasse verwendet wird. Grundsätzlich verwendet die Dateiklasse den Container, um Änderungen lokal zu speichern, bevor eine endgültige Version in einer tatsächlichen Datei gespeichert wird. Einige der Methoden werden daher direkt von der Containerklasse auf die Dateiklasse übertragen. (Zum Beispiel, Resize() .)

Ich habe gerade die Methoden in der Dateiklasse definiert, um ihre Varianten der Containerklasse aufzurufen. Zum Beispiel:

void FileClass::Foo()
{
    ContainerMember.Foo();
}

Dies wird jedoch zunehmend zu einem Ärgernis. Gibt es eine bessere Möglichkeit, dies zu tun?

Hier ist ein vereinfachtes Beispiel:

class MyContainer
{
    // ...

    public:

    void Foo()
    {
        // This function directly handles the object's
        // member variables.
    }
}

class MyClass
{
    MyContainer Member;

    public:

    void Foo()
    {
        Member.Foo();

        // This seems to be pointless re-implementation, and it's
        // inconvenient to keep MyContainer's methods and MyClass's
        // wrappers for those methods synchronized.
    }
}

7voto

Xeo Punkte 126280

Nun, warum nicht einfach privat erben von MyContainer und stellen Sie die Funktionen, die Sie einfach weiterleiten wollen, mit einer using Erklärung? Das nennt man "Implementing MyClass in Bezug auf MyContainer .

class MyContainer
{
public:
    void Foo()
    {
        // This function directly handles the object's
        // member variables.
    }

    void Bar(){
      // ...
    }
}

class MyClass : private MyContainer
{
public:
    using MyContainer::Foo;

    // would hide MyContainer::Bar
    void Bar(){
      // ...
      MyContainer::Bar();
      // ...
    }
}

Jetzt können "Außenstehende" direkt anrufen Foo , während Bar ist nur zugänglich innerhalb von MyClass . Wenn Sie nun eine Funktion mit demselben Namen erstellen, wird die Basisfunktion ausgeblendet und Sie können Basisfunktionen auf diese Weise einpacken. Natürlich müssen Sie jetzt den Aufruf der Basisfunktion vollständig qualifizieren, sonst geraten Sie in eine endlose Rekursion.


Wenn Sie außerdem die (nicht polymorphe) Unterklassifizierung von MyClass dann ist dies einer der seltenen Fälle, in denen die geschützte Vererbung tatsächlich nützlich ist:

class MyClass : protected MyContainer{
  // all stays the same, subclasses are also allowed to call the MyContainer functions
};

Nicht polymorph, wenn Ihr MyClass hat keinen virtuellen Destruktor.

1voto

Zan Lynx Punkte 51045

Ja, die Pflege einer solchen Proxy-Klasse ist sehr lästig. Ihre IDE hat vielleicht ein paar Werkzeuge, die das Ganze ein wenig einfacher machen. Oder Sie können vielleicht ein IDE-Add-on herunterladen.

Aber das ist normalerweise nicht sehr schwierig, es sei denn, Sie müssen Dutzende von Funktionen, Überschreibungen und Vorlagen unterstützen.

Ich schreibe sie normalerweise so:

void Foo()      { return Member.Foo(); }
int  Bar(int x) { return Member.Bar(x); }

Es ist schön symmetrisch. In C++ kann man ungültige Werte in ungültigen Funktionen zurückgeben, da Vorlagen so besser funktionieren. Aber man kann das Gleiche verwenden, um anderen Code schöner zu machen.

1voto

joce Punkte 9206

Das ist Delegationsvererbung und ich weiß nicht, ob C++ einen Mechanismus bietet, der dabei hilft.

1voto

filip-fku Punkte 3225

Überlegen Sie, was in Ihrem Fall sinnvoll ist - Komposition (hat eine) oder Vererbung (ist eine) Beziehung zwischen MyClass und MyContainer.

Wenn Sie solchen Code nicht mehr haben wollen, müssen Sie sich auf Implementierungsvererbung beschränken (MyContainer als Basis/Abstrakte Basisklasse). Sie müssen jedoch sicherstellen, dass dies in Ihrer Anwendung tatsächlich Sinn macht und Sie nicht nur für die Implementierung vererben (Vererbung für die Implementierung ist schlecht).

Im Zweifelsfall ist das, was Sie haben, wahrscheinlich in Ordnung.

EDIT: Ich bin mehr daran gewöhnt, in Java/C# zu denken und habe die Tatsache übersehen, dass C++ die größere Vererbungsflexibilität hat, die Xeo in seiner Antwort verwendet. Das fühlt sich einfach wie eine gute Lösung in diesem Fall.

0voto

tp1 Punkte 288

Diese Funktion, die Sie benötigen, um große Mengen an Code zu schreiben, ist eigentlich eine notwendige Funktion. C++ ist eine ausführliche Sprache, und wenn Sie versuchen, das Schreiben von Code mit C++ zu vermeiden, wird Ihr Entwurf nie sehr gut sein.

Das eigentliche Problem bei dieser Frage ist jedoch, dass die Klasse kein Verhalten hat. Sie ist nur ein Wrapper, der nichts tut. Jede Klasse muss etwas anderes tun, als nur Daten weiterzugeben.

Das Wichtigste ist, dass jede Klasse die richtige Schnittstelle hat. Diese Anforderung macht es notwendig, Weiterleitungsfunktionen zu schreiben. Der Hauptzweck jeder Mitgliedsfunktion besteht darin, die Arbeit zu verteilen, die todos Datenmitglieder. Wenn Sie nur ein Datenmitglied haben und noch nicht entschieden haben, was die Klasse tun soll, dann haben Sie nur Weiterleitungsfunktionen. Sobald Sie weitere Mitgliedsobjekte hinzufügen und entscheiden, was die Klasse tun soll, werden sich Ihre Weiterleitungsfunktionen in etwas Sinnvolleres verwandeln.

Eine Sache, die dabei helfen wird, ist, die Klassen klein zu halten. Wenn die Schnittstelle klein ist, wird jede Proxy-Klasse nur eine kleine Schnittstelle haben und die Schnittstelle wird sich nicht sehr oft ändern.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X