2016-05-26 12 views
1

Ich habe eine Basisklasse, die aus einer anderen Klasse besteht (nennen wir sie Komponente). Wenn ich von der Base-Klasse erben, ist es möglich, der Component-Klasse Funktionalität hinzuzufügen (vorausgesetzt, Sie können den Base-Code nicht ändern)? Ich möchte grundsätzlich eine 'Derived :: Component :: foo' Funktion.Kann die Funktion der geschachtelten Klassenmitglieder innerhalb der abgeleiteten Klasse nicht definieren

#include <iostream> 

class Base 
{ 
    public: 
     void Print() { std::cout << c.data; } 

     class Component 
     { 
      public: 
       int data; 
     }; 
     Component c; 
}; 

class Derived : public Base 
{ 
    private: 
     void Component::foo(int value) 
     { 
      this->data = value; 
     } 
    public: 
     void bar(int value) 
     { 
      this->c.foo(value); 
     } 
    }; 

int main() { 
    Derived d; 
    d.bar(4); 
    d.Print(); 
} 

Dieser Code gibt den folgenden Fehler unter G ++ 4.8 auf Ubuntu:

Fehler: kann nicht Memberfunktion 'Basis :: Component :: foo' in 'Abgeleitet'

+0

Das ist in keiner Situation gültig: Sie müssen die Funktion in der Klassendeklaration definieren. – pingul

+0

Sie können kein Mitglied einer Klasse innerhalb einer anderen Klasse definieren. – kfsone

+0

Gibt es eine Möglichkeit, eine Derived :: Component :: foo Elementfunktion hinzuzufügen? – ruslank

Antwort

1

Sie müssen definieren, erklären, die foo Funktion in der Component Klasse. Und dann definieren sie im Inneren des Component selbst:

#include <iostream> 

class Base 
{ 
public: 
    void Print() { std::cout << c.data; } 

    class Component 
    { 
    public: 
     int data; 
     void foo(int value) 
     { 
      data = value; 
     } 
    }; 

    Component c; 
}; 

class Derived : public Base 
{ 
private: 
public: 
    void bar(int value) 
    { 
     c.foo(value); 
    } 
}; 

int main() { 
    Derived d; 
    d.bar(4); 
    d.Print(); 
} 

oder außerhalb aller Klassen:

#include <iostream> 

class Base 
{ 
public: 
    void Print() { std::cout << c.data; } 

    class Component 
    { 
    public: 
     int data; 
     void foo(int value); 
    }; 

    Component c; 
}; 

void Base::Component::foo(int value) 
{ 
    data = value; 
} 

class Derived : public Base 
{ 
private: 
public: 
    void bar(int value) 
    { 
     c.foo(value); 
    } 
}; 

int main() { 
    Derived d; 
    d.bar(4); 
    d.Print(); 
} 
+0

Funktioniert das, wenn ich keinen Zugriff auf den Quellcode für Base habe? – ruslank

+0

Wenn Sie 'Base' nicht ändern können, um die' foo() 'Deklaration zu' Component' hinzuzufügen, dann wird nein. Eine abgeleitete Klasse kann einfach keine Mitglieder zur geschachtelten Klasse einer Basis hinzufügen und kann sicherlich keine Implementierung für eine Methode definieren, die nicht deklariert wurde. –

2

[..] add functionality [..] (assumming you can't modify the Base code) [..]

Je nachdem, wie die tatsächliche Basisklasse in Frage aussieht, können Sie versuchen, erhalten, indem mit einfachen Subklassifizieren der Component:

/* using struct to have public accessibility */ 
struct Base { 
    struct Component { 
    int data; 
    virtual ~Component() {} // ABSOLUTELY NECESSARY 
    }; 
    std::unique_ptr<Component> component; // ABSOLUTELY NECESSARY 

    void print(void) { 
    std::cout << component->data << endl; 
    } 
}; 

/* The decorated component, with the additional functionality */ 
struct DecoratedComponent : public Base::Component { 
    void set(int d) { 
    data = d; 
    } 
}; 

Dann wird ein Wenn es eine Möglichkeit gibt, die Komponente zu setzen, müssen Sie Ihre dekorierte Komponente übergeben (Hinweis: Wenn der Status beibehalten werden soll, können Sie auch eine Component Instanz in Ihre dekorierte Komponentenklasse einfügen, was eine echte Verwendung des Decorator-Musters darstellt):

Base the_base; 
auto the_component = std::make_unique<DecoratedComponent>(); 
// Inject the decorated component 
the_base.component = the_component; 
the_component.set(42); 
the_base.print(); // 42 

Dies funktioniert nur, wenn die Basis es ist Komponente entweder einen Verweis oder eine Art Zeiger zu speichern/Zugriff verwendet. Wenn die Basis die Lebensdauer der Komponente verwaltet, muss die Component darüber hinaus über einen virtuellen Destruktor verfügen.

+0

Danke, dieser Ansatz ist hilfreich für die Erweiterung der Komponentenfunktionalität. Im Idealfall könnten wir die 'DecoratedComponent' und andere neue Base-Methoden in einer Derived-Klasse kombinieren. Gibt es einen sauberen Weg, das zu tun? – ruslank

+0

@ruslank Hm ... du meinst, wenn, z.B. würden Sie auch "Base" ableiten? Nun, Sie könnten 'DecoratedComponent' (die Deklaration) zu einem Mitglied dieser Unterklasse machen. –