2016-04-26 8 views
1

Bitte beachten Sie das folgende Szenario:C++ abgeleitete Basisklasse Friend-Funktion Zugriff auf private bei Parent?

class A 
    { 
    friend void B::Itemfunction(); 
    private: 
    int number; 
    int size; 
    public: 
    Randomfunction(); 
    } 

    class B : public A 
    { 
    private: 
    string Random; 
    public: 
    void Itemfunction(); 
    void CheckLog(); 

    } 

es möglich wäre, für ein Objekt gemacht in Itemfunction vom Typ A auf die privaten Datenelemente von obj zugreifen? Wie zum Beispiel:

void B::Itemfunction(){ 
    A obj; 
    //Possible to do... 
    obj.number = 2; 
    } 

Ich verstehe, dass die abgeleitete Klasse B alle öffentlichen Teile von A zugreifen kann, aber wenn ich die privaten Teile zuzugreifen wäre dies der richtige Weg, es zu tun nur eine Funktion (Itemfunction) gesucht ? Ich möchte nur sehen, ob mein Verständnis stimmt.

Prost

Antwort

1

In Ihrem Code, wo Sie Itemfunction implementieren, Sie A lokal ein neues, völlig unabhängig Objekt des Typs zu schaffen. In der Vererbung hat Ihr Objekt B ein internes Unterobjekt vom Typ A. Sie können auf die Felder A direkt innerhalb von B zugreifen. Sie können jedoch nicht auf private Mitglieder zugreifen. Dein Freundschaftstrick wird nicht funktionieren. Sie können eine Methode B eines Freundes nicht erklären, bis Sie B s Definition sehen, aber B kann nicht definiert werden, bis A definiert ist, und wie Sie sehen können, gehen wir in Kreisen. Was Sie stattdessen tun können, ist dieses Mitglied geschützt zu machen:

class A 
{ 
    protected: 
    int number; 
    private: 
    int size; 
    public: 
    Randomfunction(); 
} 

void B::Itemfunction() { 
    number = 2; 
} 
+0

Vielen Dank für die Antwort, ah ich sehe das Thema in Kreisen jetzt gehen. Ich denke, abgesehen von der Lösung, die Sie beschrieben haben, sollte Klasse B ein Freund von A auch richtig funktionieren? Oder würde es Probleme geben, eine abgeleitete Klasse und ein Freund zu sein? –

+0

Denken Sie an die Bedürfnisse Ihres Programms. Wenn 'A' Freunde' B' so dass 'B' Zugriff hat, was dann von Kindern' C' oder 'D'? Die Freundschaft wird nicht skaliert, wenn Sie Unterklassen hinzufügen. [Geschützter Zugriff wird] (http://en.cppreference.com/w/cpp/language/access), wenn Sie das wollen. – user4581301

+0

@ afc_1995 'protected' wurde entwickelt, um genau dieses Problem zu lösen, also sollten Sie' protected' wirklich verwenden. Wenn "B" mit "A" befreundet ist, kann es auf alles zugreifen, einschließlich privater Mitglieder. Der ganze Punkt, sowohl geschützt als auch privat zu sein, ist so, dass A entscheiden kann, wozu seine Kinder Zugang haben. Gibt es irgendeinen Grund, warum du Freundschaft lieber schützt? –

1

Nein, es ist nicht möglich. Sie können eine Klassenmemberfunktion für eine Klasse, die noch nicht vollständig deklariert ist, nicht mit Freunden verknüpfen.

Der einzige Weg, in diesem Fall (da class B muss ein vollständig class A erklärt zu erben), zu übermitteln ist class B; und Freund der ganze Klasse deklariert:

#include <iostream> 
#include <string> 

    class B; 

    class A 
    { 
    // friend void B::Itemfunction(); 
    friend class B; 
    private: 
    int number; 
    int size; 
    public: 
    void Randomfunction(); 
    }; 

    class B : public A 
    { 
    private: 
    std::string Random; 
    public: 
    void Itemfunction(); 
    void CheckLog(); 

    }; 

int main() 
{ 
} 

Live Demo

+0

Vielen Dank für die klare Erklärung! Sehr geschätzt - ich muss B vielleicht zu einem Freund von A machen, damit es funktioniert, dann scheint es .... habe die Notwendigkeit nicht erkannt, zu deklarieren - toller Tipp! –

+0

Dann ist es vorzuziehen, dieses Mitglied geschützt statt privat zu machen und nicht die ganze Klasse Freund zu machen. – Slava

+0

@Slava Sicher, guter Punkt. –

0

Dies hat ein Huhn und Ei-Problem. Beide B müssen vollständig für A definiert werden, um B::Itemfunction zu sehen.

class A 
{ 
    friend void B::Itemfunction(); <-- Itemfunction does not exist yet 
private: 
    int number; 
    int size; 
public: 
    int Randomfunction(); 
}; 

class B: public A 
{ 
private: 
    std::string Random; 
public: 
    void Itemfunction(); 
    void CheckLog(); 

}; 

den Auftrag Swapping nicht entweder weil B Bedürfnisse A zu definierende Arbeit von A zu erben.

class B: public A <-- A does not exist yet 
{ 
private: 
    std::string Random; 
public: 
    void Itemfunction(); 
    void CheckLog(); 

}; 

class A 
{ 
    friend void B::Itemfunction(); 
private: 
    int number; 
    int size; 
public: 
    int Randomfunction(); 
}; 

Lösung 1 nach vorne class B definieren, so weiß der Compiler, dass B existiert, auch wenn es nichts davon weiß, und dann friend die ganze Klasse, weil A nur weiß B existiert. OPs friend Beziehung wird beibehalten.

class B; <-- forward definition of B 
class A 
{ 
    friend class B; <-- friending all of B, not just the function 
private: 
    int number; 
    int size; 
public: 
    int Randomfunction(); 
}; 

class B: public A 
{ 
private: 
    std::string Random; 
public: 
    void Itemfunction(); 
    void CheckLog(); 

}; 

ABER! Alle B haben jetzt vollständigen Zugriff auf alle A. Wenn A möchte size oder andere Mitglieder versteckt und unter seiner Kontrolle, hart zu halten. B kann alle Funktionen von A aufrufen und alle Mitgliedsvariablen von A ändern. B kann vollständig A gestochen werden.

Dies skaliert auch nicht zu anderen Unterklassen.B kann alle A sehen, aber C und können nicht.

Also sagen Sie, Sie haben ein weniger triviales Beispiel, wo A niemandem erlauben kann, mit dem Wert size zu verwirren. Vielleicht ist es die Kapazität eines internen Arrays, und wenn Sie size ändern, wird A über das Ende des zugewiesenen Speichers hinaus ausgeführt. Der Grund spielt hier keine Rolle; Für dieses Beispiel darf niemand außer Asize ändern.

Dies führt uns zu Lösung 2: protected access und Accessor-Funktionen.

class A 
{ 
protected: <-- all inheritors can access members in this block. No one else can 
    int number; 
private: <-- only A can access members in this block 
    int size; 
public: 
    int Randomfunction(); 
    int getSize() <-- accessor function to provide read-only access to size 
    { 
     return size; 
    } 
}; 

class B: public A 
{ 
private: 
    std::string Random; 
public: 
    void Itemfunction(); <-- can do anything to number and read size 
    void CheckLog(); <-- so can this 

}; 

class C: public A 
{ 
private: 
    std::string member; 
public: 
    void doStuff(); <-- and this 
    void DoOtherStuff(); <-- and this 

}; 

B und C können A::number zugreifen und A::getSize verwenden können, um den Wert von size zu sehen. number kann durch B und C geändert werden, aber size kann nicht. Wenn Sie sich Sorgen machen über die Kosten für den Aufruf einer Funktion zum Lesen size, seien Sie nicht. Wenn der Compiler mit A::getSize fertig ist, werden Sie nicht einmal wissen, dass es da ist. Es ist wahrscheinlich nicht.