Członkowie prywatni i chronieni: C ++


276

Czy ktoś może mnie oświecić co do różnicy między privatei protectedczłonków w zajęciach?

Rozumiem z konwencji najlepszych praktyk, które zmienne i funkcje, które nie są nazywane poza klasą należy private- ale patrząc na moje MFC projektu MFC wydaje korzyść protected.

Jaka jest różnica i którego powinienem użyć?

Odpowiedzi:


374

Członkowie prywatni są dostępni tylko w obrębie klasy, która je definiuje.

Członkowie chronieni są dostępni w klasie, która je definiuje, oraz w klasach dziedziczących po tej klasie.

Edycja: Oba są również dostępne dla przyjaciół z ich klasy, a w przypadku członków chronionych - dla przyjaciół z ich klas pochodnych.

Edycja 2: Używaj czegokolwiek, co ma sens w kontekście twojego problemu. Powinieneś próbować uczynić członków prywatnymi, ilekroć możesz, aby zmniejszyć sprzężenie i chronić implementację klasy podstawowej, ale jeśli nie jest to możliwe, użyj chronionych członków. Sprawdź C ++ FAQ, aby lepiej zrozumieć problem. To pytanie dotyczące chronionych zmiennych może również pomóc.


12
Link do C ++ FAQ Lite został przeniesiony na isocpp.org/wiki/faq/basics-of-inheritance
avner

134

Członkowie publiczni klasy A są dostępni dla wszystkich i dla wszystkich.

Chronione elementy klasy A nie są dostępne poza kodem A, ale są dostępne z kodu dowolnej klasy pochodnej A.

Prywatni członkowie klasy A nie są dostępni poza kodem A ani z kodu żadnej klasy pochodzącej od A.

Tak więc ostatecznie wybór między chronionym a prywatnym stanowi odpowiedź na następujące pytania: Ile zaufania jesteś gotów obdarzyć programistę klasy pochodnej?

Domyślnie załóż, że klasie pochodnej nie można ufać, i uczyń swoich członków prywatnymi . Jeśli masz bardzo dobry powód, aby zapewnić bezpłatny dostęp do wewnętrznych elementów klasy macierzystej do jej klas pochodnych, możesz je zabezpieczyć.


Klasa pochodna powinna być typem klasy, a chronione dane klasy bazowej są częścią danych klasy pochodnej. Oczekuje się, że autor klasy pochodnej będzie poprawnie obsługiwał te dane lub jest to błąd. Prywatne dane w klasie bazowej są jednak czymś, o czym pisarz klasy pochodnej nie kontroluje.
CashCow 11.10.16

@CashCow the protected data of the base class is part of the data of the derived class.Rzeczywiście. Czy nie lepiej jest zatem, aby autor klasy pochodnej zadeklarował te dane w swojej klasie zamiast mojej? ... :-) ... The writer of the derived class is expected to handle this data properly or it is a bug.W schemacie NVI celem jest uczynienie wszystkiego prywatnym, w tym metody, aby ograniczyć szkody, jakie pisarz klas pochodnych mógłby wyrządzić hierarchii. Metody chronione są już potencjalnym problemem. Nie jestem przekonany, że pogłębienie tego poprzez użycie stanu chronionego jest właściwym podejściem.
paercebal,

Może to być, co wymagałoby posiadania wirtualnych „modułów pobierających” w klasie podstawowej, aby uzyskać do niego dostęp. I chociaż możesz mieć klasy pośrednie, które robią różne sposoby implementacji wzorca danych, nie zawsze jest to praktyczne. Na przykład „wzorzec”, powszechny w językach, które nie mają modyfikatora „const”, chociaż nie jest to konieczne przez większość czasu w C ++, to posiadanie klasy bazowej tylko do odczytu i zapisywalnych klas pochodnych. W C ++ może to być również miłe po prostu dlatego, że potrzebujesz więcej niż jednego możliwego sposobu ładowania (inicjalizacji) danych.
CashCow

Można to zrobić na różne sposoby. Zaprzyjaźnij się z klasami serializacji. Umieść wszystkie swoje dane w strukturze z dostępem publicznym, ale twoja klasa ma prywatnego członka tej zmiennej ... Chronieni członkowie i klasy pochodne, aby załadować je z dowolnego źródła, czasem jest łatwiejsze.
CashCow

63

Dostęp do członków chronionych można uzyskać z klas pochodnych. Prywatne nie mogą.

class Base {

private: 
  int MyPrivateInt;
protected: 
  int MyProtectedInt;
public:
  int MyPublicInt;
};

class Derived : Base
{
public:
  int foo1()  { return MyPrivateInt;} // Won't compile!
  int foo2()  { return MyProtectedInt;} // OK  
  int foo3()  { return MyPublicInt;} // OK
};‌‌

class Unrelated 
{
private:
  Base B;
public:
  int foo1()  { return B.MyPrivateInt;} // Won't compile!
  int foo2()  { return B.MyProtectedInt;} // Won't compile
  int foo3()  { return B.MyPublicInt;} // OK
};

To zależy od „najlepszych praktyk”. Jeśli istnieje choćby niewielka możliwość, że ktoś może chcieć czerpać nową klasę z istniejącej klasy i potrzebować dostępu do wewnętrznych członków, uczyń ich chronionymi, a nie prywatnymi. Jeśli są prywatne, twoja klasa może być trudna do odziedziczenia.


3
Zaczynam się różnić: jeśli istnieje niewielka możliwość, że żadna podklasa nie będzie jej potrzebować, uczyń ją prywatną. Chyba, że zamierzają się klasa podklasy, należy użyć wzoru metody szablonu.
xtofl,

23

Powodem, dla którego MFC preferuje ochronę, jest to, że jest to framework. Prawdopodobnie chcesz podklasować klasy MFC. W takim przypadku potrzebny jest chroniony interfejs, aby uzyskać dostęp do metod niewidocznych dla ogólnego użycia klasy.


9

Wszystko zależy od tego, co chcesz zrobić i od tego, co mają widzieć klasy pochodne.

class A
{
private:
    int _privInt = 0;
    int privFunc(){return 0;}
    virtual int privVirtFunc(){return 0;}
protected:
    int _protInt = 0;
    int protFunc(){return 0;}
public:
    int _publInt = 0;
    int publFunc()
    {
         return privVirtFunc();
    }
};

class B : public A
{
private:
    virtual int privVirtFunc(){return 1;}
public:
    void func()
    {
        _privInt = 1; // wont work
        _protInt = 1; // will work
        _publInt = 1; // will work
        privFunc(); // wont work
        privVirtFunc(); // wont work
        protFunc(); // will work
        publFunc(); // will return 1 since it's overridden in this class
    }
}

6

Atrybuty i metody oznaczone jako protectedsą - w przeciwieństwie do prywatnych - nadal widoczne w podklasach.

Chyba, że ​​nie chcesz używać ani nie umożliwiać zastąpienia metody w możliwych podklasach private.


2
Klasa pochodna może zastąpić prywatne funkcje wirtualne swojej bazy
James Hopkin

6

Spójrz na pytanie dotyczące chronionych zmiennych członkowskich . Zalecane jest użycie wartości domyślnej private (podobnie jak C ++ classses do), aby zmniejszyć sprzężenie. Chronione zmienne składowe są zawsze złym pomysłem, chronione funkcje składowe można wykorzystać np. Do wzorca metody szablonu.


Zabawne, edytowałem to w swoim poście, zanim zobaczyłem twój. Głosowane, ponieważ ptaki z piór natkną się na ten sam link :)
Firas Assaad

4

Dostęp do członków chronionych mogą uzyskać wyłącznie potomkowie klasy i kod w tym samym module. Członkowie prywatni mogą być dostępni tylko przez klasę, w której są zadeklarowani, oraz przez kod w tym samym module.

Oczywiście funkcje znajomych wyrzucają to przez okno, ale no cóż.


4

członkowie prywatni są dostępni tylko wewnątrz klasy, członkowie chronieni są dostępni w klasie i klasach pochodnych. Jest to funkcja dziedziczenia w językach OO.

Możesz mieć prywatne, chronione i publiczne dziedziczenie w C ++, które określi, do których klas pochodnych może uzyskać dostęp w hierarchii dziedziczenia. Na przykład C # ma tylko dziedzictwo publiczne.


3

prywatny = dostępny tylko dla statku-matki (klasa podstawowa) (tzn. tylko mój rodzic może wejść do sypialni mojego rodzica)

chroniony = dostępny dla statku-matki (klasa podstawowa) i jej córek (tzn. tylko mój rodzic może wejść do sypialni mojego rodzica, ale dał synowi / córce pozwolenie na wejście do sypialni rodzica)

public = dostępny dla statku-matki (klasa podstawowa), córki i wszystkich innych (tj. tylko mój rodzic może wejść do sypialni mojego rodzica, ale jest to impreza domowa - mi casa su casa)


2

Ponieważ żadna funkcja publiczna nie jest potrzebna do pobierania i aktualizowania chronionych elementów w klasie pochodnej, zwiększa to efektywność kodu i zmniejsza ilość kodu, który musimy napisać. Jednak programista klasy pochodnej powinien być świadomy tego, co robi.


Zawsze możesz użyć funkcji wbudowanej zaimplementowanej w deklaracji klasy. Kompilator zoptymalizuje to (i na przykład byłby to dobry sposób na wymuszenie dostępu tylko do odczytu do prywatnej zmiennej członka).
Paul Sanders

2

privatejest preferowany dla danych członka. Członkowie klas C ++ są privatedomyślnie.

publicjest preferowany dla funkcji składowych, choć jest to kwestia opinii. Przynajmniej niektóre metody muszą być dostępne. publicjest dostępny dla wszystkich. Jest to najbardziej elastyczna opcja i najmniej bezpieczna. Każdy może z nich korzystać i każdy może ich niewłaściwie używać.

privatejest w ogóle niedostępny. Nikt nie może ich używać poza klasą i nikt nie może ich nadużywać. Nawet w klasach pochodnych.

protectedjest kompromisem, ponieważ można go stosować w klasach pochodnych. Kiedy wywodzisz się z klasy, dobrze rozumiesz klasę podstawową i uważasz, aby nie nadużywać tych członków.

MFC to opakowanie C ++ dla Windows API, preferuje publici protected. Klasy generowane przez Visual Studio Kreator mają brzydki mieszankę protected, publicoraz privateczłonków. Ale istnieje pewna logika dla samych klas MFC.

Członkowie tacy SetWindowTextsą, publicponieważ często trzeba uzyskać do nich dostęp.

Członkowie, na przykład OnLButtonDown, obsługują powiadomienia otrzymane przez okno. Nie powinny być one dostępne, dlatego są protected. Nadal możesz uzyskać do nich dostęp w klasie pochodnej, aby zastąpić te funkcje.

Niektórzy członkowie muszą wykonywać wątki i pętle wiadomości, nie należy do nich uzyskiwać dostępu ani nadpisywać, więc są zadeklarowani jako private

W strukturach C ++ członkowie są publicdomyślnie. Struktury są zwykle używane tylko do danych, a nie do metod, dlatego publicdeklaracja jest uważana za bezpieczną.


1
Piszesz „Członkowie klas C ++ są domyślnie chronieni”. Zgodnie ze standardem są one domyślnie prywatne lub publiczne, w zależności od słowa kluczowego użytego w definicji (14p3). Czy Microsoft odbiega od standardu tutaj?
Alexander Klauer

@AlexanderKlauer Myliłem się, privatedomyślnie jest to Visual Studio. To privatedomyślnie w gcc, jak również, że nigdy nie jest publicdomyślnie. Chyba że znowu się mylę. Nie mogę znaleźć standardu, o którym mowa.
Barmak Shemirani,

Przepraszam, powinienem był bardziej konkretny. Miałem na myśli standard C ++ 17. Standard C ++ 11 ma to samo brzmienie w 11p3. Czy możesz zaktualizować swoją odpowiedź? Dzięki!
Alexander Klauer,

1

Dostęp do członka prywatnego można uzyskać tylko w tej samej klasie, w której zadeklarował, gdzie jako członek chroniony można uzyskać dostęp w klasie, w której jest zadeklarowany wraz z klasami przez niego dziedziczonymi.


1
  • Prywatny : jest to specyfikator dostępu. Domyślnie zmienne instancji (członka) lub metody klasy w c ++ / java są prywatne. Podczas dziedziczenia kod i dane są zawsze dziedziczone, ale nie są dostępne poza klasą. Możemy zadeklarować naszych członków danych jako prywatnych, aby nikt nie mógł dokonywać bezpośrednich zmian w naszych zmiennych członkowskich, a także zapewnić publiczne obiekty pobierające i ustawiające w celu zmiany naszych prywatnych członków. Ta koncepcja jest zawsze stosowana w regule biznesowej.

  • Protected : Jest to także specyfikator dostępu. W C ++ chronione elementy są dostępne w klasie i klasie dziedziczonej, ale nie poza nią. W Javie chronione elementy są dostępne w obrębie klasy, dla odziedziczonej klasy, a także dla wszystkich klas w tym samym pakiecie.


0

Dostęp do chronionego niestatycznego członka klasy podstawowej mogą uzyskać członkowie i przyjaciele dowolnej klasy wywodzącej się z tej klasy podstawowej, korzystając z jednego z następujących sposobów:

  • Wskaźnik do bezpośrednio lub pośrednio pochodnej klasy
  • Odwołanie do bezpośrednio lub pośrednio pochodnej klasy
  • Obiekt klasy bezpośrednio lub pośrednio pochodnej

0

Prywatny: dostępny przez funkcje członka klasy i funkcję przyjaciela lub klasę przyjaciela. W przypadku klasy C ++ jest to domyślny specyfikator dostępu.

Chronione: Dostępne przez funkcje członka klasy, funkcję znajomego lub klasę znajomego i klasy pochodne.

  • Możesz zachować zmienną lub funkcję członka klasy (nawet typedefs lub klasy wewnętrzne) jako prywatne lub chronione zgodnie z wymaganiami.
  • Przez większość czasu zachowujesz członka klasy jako prywatny i dodajesz funkcje get / set do enkapsulacji. Pomaga to w utrzymaniu kodu.
  • Zasadniczo funkcja prywatna jest używana, gdy chcesz zachować modułowość funkcji publicznych lub wyeliminować powtarzający się kod zamiast pisać cały kod w pojedynczej funkcji. Pomaga to w utrzymaniu kodu.

Zobacz ten link, aby uzyskać więcej szczegółów.


-2

modyfikatory dostępu prywatnego i chronionego są jednym i tym samym, że dostęp do chronionych członków klasy podstawowej można uzyskać poza zakresem klasy podstawowej w klasie potomnej (pochodnej). To samo dotyczy dziedziczenia. Ale dzięki modyfikatorowi prywatnemu członkowie klasy podstawowej mogą być dostępni tylko w zakresie lub kodzie klasy podstawowej, a jej funkcje znajomych są tylko


5
Jaką wartość dodaje twoja odpowiedź w porównaniu z innymi odpowiedziami?
Hermann Döppes,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.