2016-07-16 19 views
1

Längere Diskussion dieses hier: Why do objects of the same class have access to each other's private data?C++ Verweis auf dieselbe Klasse Exposes Private Members

Einfaches Beispiel unter Verwendung Linie mit einer ganzen Zahl Länge Objekte. Die Überladungsfunktion operator+ hat Zugriff auf die private Länge der anderen Zeile (der Parameter const Line &line, auch bekannt als die Zeile, die der Zeile this hinzugefügt wird). Dasselbe gilt für eine Nicht-Operator-Überlastfunktion (printOtherLine) und eine Friend-Funktion (printFriendLine). Die als Parameter übergebene Linie ist wiederum nicht this Objekt.

Warum ist das der Fall?

#include <iostream> 

class Line 
{ 
    public: 
     Line() 
     { 
     length = 0; 
     } 
     Line(int length) 
     { 
     this->length = length; 
     } 
     Line operator+(const Line &line) 
     { 
     Line newLine(this->length + line.length); // I would have thought 
                // this would be line.getLength() 
                // instead of line.length 
     return newLine; 
     } 
     int getLength() 
     { 
     return length; 
     } 
     void printOtherLine(const Line &otherLine){ 
     std::cout << "Other Line: " << otherLine.length << std::endl; 
     } 
     void printLine(int lineNumber){ 
     std::cout << "Line " << lineNumber << ": " << this->length << std::endl; 
     } 
     friend void printFriendLine(const Line &friendlyLine); 
    private: 
     int length; 
}; 

void printFriendLine(const Line &friendlyLine){ 
    std::cout << "Friendly Line: " << friendlyLine.length << std::endl; 
} 

// This function will not compile 
// void printUnassociatedLine(const Line &line){ 
// std::cout << "Unassociated Line: " << line.length << std::endl; 
// } 

int main() 
{ 
    Line l1(10); 
    l1.printLine(1); 
    Line l2(15); 
    l2.printLine(2); 
    Line l3 = l1 + l2; 
    l3.printLine(3); 
    Line l4(7); 
    l3.printOtherLine(l4); 
    printFriendLine(l4); 
    return 0; 
} 

Ausgang:

Line 1: 10 
Line 2: 15 
Line 3: 25 
Other Line: 7 
Friendly Line: 7 
+0

Hat die Frage, auf die Sie jetzt im Update verlinkt sind, Ihre Frage beantwortet? Wenn ja, schließe ich das für dich. Oder du kannst es löschen, wenn meine Antwort nicht mehr bietet, als du dort gefunden hast. –

Antwort

0

In C++ den gesamten Code einer Klasse X hat Zugriff auf alle X-Teile, unabhängig davon, welches Objekt.

Dazu gehört auch Code in Klassendefinitionen innerhalb X. verschachtelt

In Bezug auf Gründe, die Spekulation meinerseits informiert ist, eine post-Rationalisierung, aber der Zweck Zugangsbeschränkungen ist eine Klasse einfacher zu machen richtig zu verwenden und mehr schwer falsch zu verwenden, für anderen Code. Der eigene Code der Klasse ist vertrauenswürdig und muss trotzdem alle Klassen verwenden. Es macht also wenig Sinn, den eigenen Code der Klasse zu beschränken.


Es gibt eine interessante technische Frage in Bezug auf den Zugang zu protected Datenelemente. Ein geschütztes Datenelement, das in eine Klasse Base eingeführt wird, kann direkt in einer abgeleiteten Klasse Derived zugreifen, jedoch nur für Objekte, deren statisch bekannter Typ Derived oder von Derived abgeleitete Klassen ist. Dies stellt sicher, dass Sie nicht versehentlich Zugriff auf Ihren Code erhalten und ihn von den Klasseninternessen einer anderen Person abhängig machen können, indem Sie einfach von einer gemeinsamen Basisklasse ableiten.

class Base 
{ 
protected: 
    int x_  = 666; 
}; 

class Derived 
    : public Base 
{ 
public: 
    auto uh_oh(Base const& other) const 
     -> int 
    { return x_ * other.x_; }   //← Nyet! 
}; 

auto main() 
    -> int 
{ 
    Derived a 
    Derived b; 
    return a.uh_oh(b); 
} 

Es gibt zwei übliche Problemumgehungen, wo man diesen Zugriff wirklich benötigt. Eine besteht darin, eine Accessor-Funktion in der Basisklasse einzuführen. Und das andere ist eine Art System Schlupfloch für Mitglied Zeiger wie diese, zu verwenden:

class Base 
{ 
protected: 
    int x_  = 666; 
}; 

class Derived 
    : public Base 
{ 
public: 
    auto uh_oh(Base const& other) const 
     -> int 
    { return x_ * other.*&Derived::x_; }  // A somewhat dirty trick. 
}; 

auto main() 
    -> int 
{ 
    Derived a; 
    Derived b; 
    return a.uh_oh(b); 
} 

Es gibt auch eine implizite Ausgabe von Best Practice hier: wenn Sie einen Accessor wie getLength haben, und auch Zugang zu "der" Mitglied Variable length, sollte die eine oder andere bevorzugt verwendet werden?

Nun, es könnte sein, dass man später die Implementierung ändern möchte, z.B. Die Länge kann auf irgendeine Weise berechnet werden, anstatt direkt gespeichert zu werden, und dann kann es weniger Arbeit sein, dies zu tun, wenn der Code im Allgemeinen die Accessor-Funktion verwendet. Aber auf der anderen Seite kann es mehr Arbeit sein, Code mit dem Accessor zu schreiben, und es kann mehr Arbeit sein, solchen Code zu debuggen. Zumindest soweit ich das beurteilen kann, liegt es im gesunden Menschenverstand, Bauchgefühl Entscheidungen zu treffen. ;-)