2012-06-15 6 views
5

Angenommen, wir zwei Klassen haben:Wie kann eine Klasse nur auf bestimmte private Mitglieder einer anderen Klasse zugreifen?

class Base 
{ 
private: 
    int x; 
public: 
    void f(); 
}; 

class Foo 
{ 
    // some variables and methods 
}; 

Jetzt kann jeder Base::f() nennen, aber ich möchte nur Foo der Lage sein, dies zu tun.

Um diesen Effekt zu erreichen, können wir Base::f() privat machen und Foo als Freund erklären:

class Base 
{ 
private: 
    int x; 
    void f(); 
    friend Foo; 
}; 

Das Problem bei diesem Ansatz ist, dass Foo den Zugang zu beiden Base::f() hat und Base::x (und sogar zu andere private Mitglieder von Base). Aber ich möchte Foo Zugriff nur auf Base::f() haben.

Gibt es eine Möglichkeit für eine Klasse (oder eine Funktion), nur bestimmten privaten Mitgliedern einer anderen Klasse Zugriff zu gewähren? Oder vielleicht könnte jemand eine bessere Herangehensweise an mein Problem vorschlagen?

EDIT:

Ich werde versuchen, die Zugriffsbeschränkung muss ich angeben. Erstens ist Base eine Schnittstelle in einer Bibliothek (es ist tatsächlich eine abstrakte Klasse). Der Benutzer verwendet nur die von Base abgeleiteten Klassen. Base::f() wird nur von Foo aufgerufen, die eine andere Klasse in der Bibliothek ist. Es ist wichtig, Base::f() vom Benutzer zu verstecken, weil nur Foo weiß, wann es aufgerufen werden soll. Zur gleichen Zeit sollte Foo die anderen Mitglieder von Base nicht durcheinander bringen.

+0

Sie könnten 'f()' geschützt machen und geschützte Vererbung verwenden, denke ich. – chris

+0

Aber 'Foo' ist nicht von' Base' abgeleitet. – miloszmaki

+0

Es war nur ein Gedanke. Sie müssten es ableiten. Nachdem ich die 'BaseData'-Antwort gesehen hatte, ging ich damit jedoch weiter. – chris

Antwort

6

Sehr hacky, aber dies wird sehr feinkörnigen Zugriff ermöglichen.

class Base 
{ 
private: 
    int x; 
    void f(); 
    friend class Base_f_Accessor; 
}; 

class Base_f_Accessor 
{ 
private: 
    static void f(Base & b) { b.f(); } 
    friend class Foo; 
} 

class Foo 
{ 
    // some variables and methods 
}; 
+0

Ich mag diesen Ansatz, da er die Implementierungsdetails von 'Base_f_Accessor' in einer CPP-Datei verbergen kann. Auf diese Weise kann 'Foo' auch in der .cpp-Datei definiert und nicht für den Benutzer verfügbar gemacht werden. – miloszmaki

4

Sie können eine andere Klasse erstellen, die die Daten für Base wie folgt enthält:

class BaseData { 
protected: 
    int x; 
}; 

class Base : public BaseData { 
    friend class Foo; 
    void f(); 
}; 

Jetzt können Foof Zugriff als Methode der Base wie man wollte, aber nicht x. Freundschaft ist nicht kommutativ. Durch die Verwendung von protected erscheint x privat für alle außer denen, die direkt von BaseData abgeleitet sind.

Ein besserer Ansatz könnte sein, Mehrfachvererbung zu verwenden Base zu definieren und nur Foo Zugang bieten zu diesen Klassen möchten Sie aus der Base herleitet.

class With_f { 
    friend class Foo; 
protected: 
    virtual void f() = 0; 
}; 

class With_g { 
protected: 
    virtual void g() = 0; 
}; 

class Base : public With_f, public With_g { 
    int x; 
    void f() {} 
    void g() {} 
}; 

Hier Foo würde einen With_f Zeiger auf Base haben müssen, aber es könnte dann die f Methode zugreifen. Foo konnte nicht auf g zugreifen.

+0

Was würde passieren, wenn Sie 'Base' zu ​​einem Freund von' BaseData' machen würden? Würden Freunde von 'Base' auch darauf zugreifen können? Ich denke, das würde besser funktionieren als Vererbung, wenn es so funktioniert. – chris

+0

@chris: Ein Freund eines Freundes ist kein Freund in C++. – jxh

+0

Dann wäre das wahrscheinlich besser als die Einführung der Vererbung. – chris

2

Es gibt keine einfache, nicht-hackische Art, das zu erreichen. C++ hat einfach keine Granularität für die Zugriffssteuerung. Sie können mit einer gewissen Vererbung spielen, aber die erhöhte Komplexität überwiegt alle Vorteile, die diese Zugriffsbeschränkung haben könnte. Dieser Ansatz wird auch nicht skaliert. Sie können nur einer Freundschaftsklasse erhöhte Berechtigungen gewähren.

0

Vielleicht ein bisschen umständlich, aber könnten Sie verschachtelte Klassen machen, wo die Verschachtelung Klasse Freund ist, dann können Sie Freunde pro verschachtelte Klasse hinzufügen. Dies gibt ein gewisses Maß an Granularität:

#include <iostream> 

class Nesting 
{ 
    friend class Foo; 
    class Nested1 
    { 
    friend class Nesting; 
    public: 
    Nested1() : i(3) { } 
    private: 
    int i; 
    } n1; 
    class Nested2 
    { 
    friend class Nesting; 
    friend class Foo; 
    public: 
    Nested2() : j(5) { } 
    private: 
    int j; 
    } n2; 
    int f() { return n1.i; } 
}; 

class Foo 
{ 
public: 
    Foo(Nesting& n1) : n(n1) { } 
    int getJ() { return n.n2.j + n.f(); } 
private: 
    Nesting& n; 
}; 

int main() 
{ 
    Nesting n; 
    Foo foo(n); 
    std::cout << foo.getJ() << "\n"; 
}