2017-02-20 1 views
0

Ich schreibe Code für den Zugriff auf private Mitglieder einer Klasse durch eine andere Freundesklasse. Der folgende Code funktioniertC++ Klasse Freundschaft

// Example program 
#include <iostream> 
#include <string> 
using namespace std; 

class Foo 
{ 
    private: 
    int a; 
    protected: 
    public: 

    friend class Bar; 


    Foo(int x) 
    { 
     a = x ; 
    } 
}; 

class Bar 
{ 
    private: 
    protected: 
    public: 
    int b; 

    Bar(Foo& f) 
    { 
     b = f.a; 
     cout << "f.a is " << f.a << endl; 
    } 

}; 

int main() 
{ 
    Foo foo(5); 
    Bar bar(foo); 

    cout << "Value of variable b is " << bar.b << endl; 
} 

Der obige Code funktioniert gut. Wenn ich jedoch auf eine private Variable von Foo über eine Funktion in der Freundesklasse Bar zugreifen möchte, kann ich dies nicht tun. Siehe Code unten

#include <iostream> 
#include <string> 
using namespace std; 

class Foo 
{ 
    private: 
    int a; 
    protected: 
    public: 

    friend class Bar; 


    Foo(int x) 
    { 
     a = x ; 
    } 
}; 

class Bar 
{ 
    private: 
    protected: 
    public: 
    int b; 

    Bar(Foo& f) 
    { 
     b = f.a; 
    } 
    void printvariable(void) 
    { 
     cout << "f.a is " << f.a << endl; 
    } 

}; 

int main() 
{ 
    Foo foo(5); 
    Bar bar(foo); 

    cout << "Value of variable b is " << bar.b << endl; 
} 

ich völlig verstehen, warum die Ausführung auf der Funktion

void printvariable(void) 
    { 
     cout << "f.a is " << f.a << endl; 
    } 

versagt, da f in ihrem Umfang nicht für die Funktion ist. Da ich jedoch Foo f im Konstruktor für Bar b übergebe, hoffe ich, Code zu schreiben, der es mir ermöglicht, auf Mitglieder in Foo zuzugreifen, ohne Foo f an die Funktion printvariable() erneut zu übergeben.

Was ist der effizienteste Weg, diesen Code zu schreiben?

+2

lange Geschichte kurz, Freundschaft ist schlecht. Tun Sie sich selbst einen Gefallen, halten Sie sich an die OOP-Prinzipien und die SOLID-Prinzipien (in diesem Fall die Verkapselung). Nicht jedes Sprachmerkmal muss verwendet werden, d. H. Goto. –

+0

Fügen Sie eine Variable vom Typ 'Foo &' zu 'Bar' hinzu und der Konstruktor weist der Variablen' f' zu. Verwenden Sie dann die Elementvariable in 'printvariable'. – user4581301

+1

@EyalPerry: Sie irren sich. Erfahren Sie mehr darüber http://www.stroustrup.com/bs_faq2.html#friend - eigentlich ist 'Freund' ein zusätzlicher, präziser, extrem feiner Zugriffsmodifikator. Es ermöglicht noch mehr Kapselung, weil es ein bestimmtes Ziel definiert, nicht wie öffentlich/geschützt, die eine unbegrenzte Anzahl von Stipendiaten erlauben. Bei der Kapselung geht es nicht darum, Dinge privat zu machen! Es geht darum, den Zugang zu denen einzuschränken, die es brauchen und von denen erwartet wird, dass sie es bekommen. – quetzalcoatl

Antwort

0

Sie können den Verweis auf f behalten. Der Code sollte sein:

class Bar 
{ 
    private: 
    protected: 
    public: 
    int b; 
    Foo& f_ref; 

    Bar(Foo& f) 
    :f_ref(f) 
    { 
     b = f.a; 
    } 
    void printvariable(void) 
    { 
     cout << "f.a is " << f_ref.a << endl; 
    } 

}; 

TEST!

0

Sie es so tun, aber wenn ich Sie wäre ich einige Getter schreiben würde, auch - Klasse Freundschaft ist nicht wirklich zu empfehlen.

class Bar { 
public: 
    Foo& ref; 

    Bar(Foo& f) 
     : ref { f } 
    { } 
    void printvariable() { 
     cout << "f.a is " << ref.a << endl; 
    } 
}; 

Btw es keinen Grund ist void in Klammern in C++ zu schreiben, verlor es seine Bedeutung von C und hat keinen Einfluss jetzt.

0

Sie liegen falsch in einem Punkt. Sie passieren in der Tat einen Verweis auf f im Ctor, aber der Konstruktor und ganze class Barerinnert sich nicht ein ganze Objekt von f. In Ihrem ursprünglichen Code, macht der Konstruktor nur die Bar Objekt den int a Teil des Objekts erinnern, so dass nur wenig später zugänglich:

class Foo 
{ 
    ... 
    friend class Bar; 
    ... 
}; 

class Bar 
{ 
    ... 
    int b; 

    Bar(Foo& f) 
    { 
     b = f.a; // <=--- HERE 
    } 

    void printvariable(void) 
    { 
     cout << "f.a is " << b << endl; // <-- now it refers B 
    } 

Bitte beachten Sie, wie Sie Ihre Ctor von Bar liest nur f.a und speichert sie in b. Von nun an erinnert sich das Bar-Objekt nur noch an b und das ist alles. Sie können die b in printvariable frei zugreifen. Es wird jedoch nicht die a -von-f-genommen-sein. Es wird b sein, das während des Konstruktors auf denselben Wert wie f.a festgelegt wurde. Seit diesem Zeitpunkt sind b und f.a völlig getrennt. So funktioniert das Kopieren von Werten.

Damit Bar ganzef, erinnern Sie müssen, na ja, erinnern ganze f:

class Bar 
{ 
    ... 
    Foo wholeThing; 

    Bar(Foo& f) 
    { 
     wholeThing = f; // <=--- HERE 
    } 

    void printvariable(void) 
    { 
     cout << "f.a is " << wholeThing.a << endl; 
    } 

jedoch wieder, es gibt einen Haken: jetzt, da wholeThing vom Typ Foo, den Konstruktor wird während wholeThing=f tatsächlich eine Kopie dieses Objekts erstellen. Genau wie es war, als b=f.a, aber jetzt erinnert es sich an eine Kopie von ganzen f.

Natürlich ist es nur eine Frage des Typs. Sie können eine Referenz anstelle von ganzen Foo speichern, aber es braucht ein bisschen andere Initialisierungssyntax:

class Bar 
{ 
    ... 
    Foo& wholeThing; 

    Bar(Foo& f) : 
     wholeThing(f)  // <=--- HERE 
    { 
          // <=--- empty 
    } 

    void printvariable(void) 
    { 
     cout << "f.a is " << wholeThing.a << endl; 
    } 
+0

Vielen Dank für Ihre Hilfe. Was sind die besten Ressourcen, auf die ich verweisen kann, um herauszufinden, wie diese Initialisierung im Hintergrund abläuft, dh Speicherverbrauch und Betriebskosten. Ich bin ein Anfänger in C++ und alle Hilfe wird sehr geschätzt. – user2877289

+0

@ user2877289: Ich verstehe, aber Entschuldigung, ich kann dir mit so viel mehr nicht helfen, was ich bereits geschrieben habe. Es gibt Tonnen von ähnlichen Ressourcen, selbst auf dem StackOverflow selbst. Suchen Sie einfach nach folgenden Begriffen: 'Parameter nach Wert übergeben ',' Parameter nach Referenz übergeben' und optional 'nach Zeiger'. Alles im Zusammenhang mit C++! sei vorsichtig damit. Sie werden einige Texte finden, die sich mit Java und C# beschäftigen, da auch die Begriffe by-value und by-reference für sie relevant und anders sind. Oder schnappen Sie sich ein C++ Tutorial oder Buch. Die Pass-by-XXX-Unterscheidung ist so wichtig, dass sie immer in der Nähe von "Methoden" oder "Funktionen" erläutert wird – quetzalcoatl

Verwandte Themen