2009-09-12 13 views
11

Jestem zdezorientowany: Myślałem, że chronione dane zostały odczytane/zapisane przez dzieci danej klasy w C++.Chronione dane w klasie nadrzędnej niedostępne w klasie podrzędnej?

Poniższy fragment nie skompilować w MS Compiler

class A 
{ 
protected: 
    int data; 
}; 

class B : public A 
{ 
    public: 

    B(A &a) 
    { 
    data = a.data; 
    } 
}; 

int main() 
{ 
    A a; 
    B b = a; 
    return 0; 
} 

komunikat o błędzie:

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86 
Copyright (C) Microsoft Corporation. All rights reserved. 

demoFail.cpp 
demoFail.cpp(12) : error C2248: 'A::data' : cannot access protected member declared in class 'A' 
     demoFail.cpp(4) : see declaration of 'A::data' 
     demoFail.cpp(2) : see declaration of 'A' 

Co robię źle?

Odpowiedz

10

Według TC++ PL, PG 404:

Klasa pochodna może uzyskać dostęp do klasy bazowej chronione członków tylko dla obiektów typu własnym .... Zapobiega to subtelnym błędom, które w przeciwnym razie wystąpiłyby, gdyby jedna z wyprowadzonych klas uszkodziła dane należące do innych klas pochodnych.

Oczywiście, oto prosty sposób rozwiązać ten problem w Twoim przypadku:

class A 
{ 
protected: 
    int data; 
}; 

class B : public A 
{ 
public: 
    B(const A &a) 
     : A(a) 
    { 
    } 
}; 

int main() 
{ 
    A a; 
    B b = a; 
    return 0; 
} 
+0

Umph. Mówiąc dokładniej, ten przypadek jest jedynie fałszywym przykładem, aby zademonstrować problem. Tak naprawdę chciałem zrobić dość intensywny odczyt danych, które są przekazywane. –

+0

W każdym razie możesz zmarnować tylko z chronionymi danymi w części A tego lub innego obiektu B. Jeśli masz instancję klasy A lub instancję C, która również wywodzi się z A, B nie ma specjalnych uprawnień do tych jako. Jeśli nie możesz skorzystać z tej porady (utwórz tę część B, kopiując ją jako podstawową część tego B, do której masz dostęp), możesz mieć problem z projektowaniem, który może wymagać większego obrazu odpowiedź. – UncleBens

+0

@rlbond: Kodowanie po snu ponownie uderza. To rozwiązało mój problem. Dzięki. :) –

0

Konstruktor B jest prywatny. Jeśli nic nie podano, w klasie domyślny modyfikator jest prywatny (dla structs jest public). Tak więc w tym przykładzie problem polega na tym, że nie można zbudować B. Gdy dodasz publiczny do konstruktora B, powstaje problem anoteryczny:

B ma prawo do modyfikowania części A, z której pochodzi, ale nie takiej, jak w tym przypadku.

Można zrobić następujące:

class A 
{ 
public: 
    A() 
     : data(0) 
    { 
    } 
    A(A &a) 
    { 
    data = a.data; 
    } 
protected: 
    int data; 
}; 

class B : public A 
{ 
public: 
    B(A &a) 
     : A(a) 
    { 
    } 
}; 

int main() 
{ 
    A a; 
    B b = a; 
    return 0; 
} 
+0

To co myślałem, ale to nie jest problem. – rlbond

+0

@jde: to właściwie literówka. Wykonanie konstruktora B public powoduje taki sam błąd. –

+0

@Paul, napraw wszelkie przypadkowe błędy w pytaniach, więc dalsze odpowiedzi nie proponują tego samego rozwiązania :) –

2

C++ standard mówi o chronionych członków non-statycznych w 11.5/1

Kiedy przyjaciel lub funkcja członkowska klasy pochodnej odwołuje się do chronionej niestatycznej funkcji członkowskiej lub chronionego niestatycznego elementu danych klasy bazowej, kontrola dostępu ma zastosowanie oprócz tych opisanych wcześniej w klauzuli 11. Z wyjątkiem tworzenia wskaźnika do elementu (5.3.1), e dostęp musi być przez wskaźnik do, odniesienie lub obiekt samej klasy pochodnej (lub dowolnej klasy pochodnej tej klasy) (5.2.5). Jeśli dostęp ma utworzyć wskaźnik do elementu, specyfikator nazwy zagnieżdżonej będzie wskazywał pochodną klasę (lub dowolną klasę pochodną tej klasy).

Oprócz wymienionych wcześniej naprawie przez innych (konstruktor B jest prywatny), myślę, że sposób rlbond będzie zrobić to dobrze. Jednak bezpośrednią konsekwencją powyższym akapicie niniejszego standardu jest to, że po to możliwe przy użyciu wskaźnika członkowskim, które zapewne jest dziura w systemie typu, oczywiście

class B : public A { 
public: 
    B(A &a){ 
    int A::*dataptr = &B::data; 
    data = a.*dataptr; 
    } 
}; 

Oczywiście, ten kod nie jest zalecane zrobić, ale pokazuje, że może dostęp to, czy naprawdę trzeba (widziałem ten sposób wykorzystywany do drukowania na std::stack, std::queue, std::priority_queue przez dostępu chronionego elementu kontenera c)

+0

hi Johannes Schaub - litb można proszę mi pokazać, jak uzyskać dostęp do członkowskim jest chroniony C w std :: stosie lub std :: kolejce mam problem z dostępem on dała mi błąd C2248: 'std :: stack <_Ty> :: c': nie może uzyskać dostępu do chronionego członka zadeklarowanego w klasie 'std :: stack <_Ty>' dzięki –

1

po prostu nie powinien skopiować A obiekt w konstruktorze B.Intencją jest, aby pozostawić inicjalizacji członków A „s do własnej konstruktora:

struct A { 
    A(const A& a): data(a.data) {} 
    protected: int data; 
}; 

struct B : public A { 
    B(const A& a): A(a) {} 
}; 
Powiązane problemy