2016-08-02 15 views
5

Đây là code:Tại sao một lớp dẫn xuất không truy cập một thành viên được bảo vệ của lớp cơ sở của nó thông qua một con trỏ tới cơ sở?

class TestA 
{ 
protected: 
    int test=12; 

public: 
    TestA() { 
     cout << "test a: " << test << endl; 
    } 
    ~TestA() { 
    } 
}; 

class TestB : public TestA 
{ 
public: 
    TestB(TestA *testA) { 
     cout << "test b: " << testA->test; 
    } 
    ~TestB() { 
    } 
}; 

int main() 
{ 
    TestA *pTestA=new TestA(); 
    TestB *pTestB=new TestB(pTestA); 
} 

Tôi đang cố gắng truy cập của một thành viên protected sử dụng một con trỏ trỏ đến một đối tượng TestA loại (do đó, một thể hiện của TestA). TestB cũng có nguồn gốc từ TestA

Tại sao tôi không thể truy cập vào nó? Chỉ có thể truy cập "bên trong" lớp mà tôi cần? Không phải bên ngoài bằng cách sử dụng con trỏ/khai báo trực tiếp?

+0

Tôi mở lại câu hỏi này là câu trả lời đề cập ở đây là tốt hơn so với bản sao cũ: [truy cập vào một thành viên bảo vệ của một lớp cơ sở trong lớp con khác] (http: // stackoverflow.com/q/11631777/514235). Đóng cửa sổ còn lại. – iammilind

+0

Câu trả lời ngắn gọn: Vì tiêu chuẩn cho biết điều này bị cấm. Theo đó, các trình biên dịch tuân thủ tiêu chuẩn sẽ ném một lỗi lên đó. YMMV, nhưng tôi thực sự gọi đây là lỗi trong tiêu chuẩn. – cmaster

+1

@cmaster (Xem mã mẫu trong câu trả lời của tôi) Nếu được phép, có thể truy cập các thành viên được bảo vệ thông qua một con trỏ kiểu 'B *' trỏ đến một thể hiện 'D1' trong hàm thành viên của' D2'. Nhưng 'D1' và' D2' là không liên quan trong thực tế. Nó có vẻ phản trực giác. – songyuanyao

Trả lời

7

Khi thừa kế công khai từ lớp cơ sở, các thành viên được bảo vệ của nó trở thành lớp dẫn xuất ' bảo vệ thành viên, có thể được truy cập trong các hàm thành viên của lớp dẫn xuất. Nhưng chúng chỉ có thể được truy cập thông qua các lớp dẫn xuất chính nó (và các lớp dẫn xuất của nó), không thể được truy cập thông qua lớp cơ sở. Vì vậy, bạn không thể truy cập thành viên test qua con trỏ của TestA, nhưng nó sẽ là tốt để truy cập nó thông qua con trỏ của TestB.

Tiêu chuẩn này cung cấp một số mẫu minh họa cho việc này. $11.4/1 Protected member access [class.protected]:

(Chỉ giữ một phần của mã ví dụ)

Một kiểm tra truy cập bổ sung ngoài những mô tả trước đó trong khoản [class.access] được áp dụng khi một thành viên dữ liệu không tĩnh hay không static chức năng thành viên là thành viên được bảo vệ của lớp đặt tên ([class.access.base]) 114 Như được mô tả trước đó, quyền truy cập vào thành viên được bảo vệ được cấp vì tham chiếu xảy ra ở một người bạn hoặc thành viên của một số lớp C. Nếu truy cập là để tạo thành một con trỏ đến thành viên ([expr.unary.op]), tên lồng nhau-specif ier sẽ biểu thị C hoặc một lớp bắt nguồn từ C. Tất cả các truy cập khác liên quan đến biểu thức đối tượng (có thể ẩn) ([expr.ref]). Trong trường hợp này, lớp của biểu thức đối tượng phải C hay một lớp dẫn xuất từ ​​C. [Ví dụ:

class B { 
protected: 
    int i; 
}; 

class D1 : public B { 
}; 

class D2 : public B { 
    void mem(B*,D1*); 
}; 

void D2::mem(B* pb, D1* p1) { 
    pb->i = 1;     // ill-formed 
    p1->i = 2;     // ill-formed 
    i = 3;      // OK (access through this) 
    B::i = 4;      // OK (access through this, qualification ignored) 
} 

- end dụ]

Tôi không chắc chắn về ý định của thiết kế của bạn , làm cho bạn bè của TestA trở thành một giải pháp đơn giản.

+0

Đây là một trong những quy tắc truy cập khó khăn hơn (đối với tôi). –

+0

Nhân tiện, "Khi công chúng kế thừa từ lớp cơ sở, các thành viên được bảo vệ của nó trở thành lớp bảo vệ" thành viên bảo vệ ": Điều đó cũng không đúng đối với thừa kế được bảo vệ? Hay thậm chí là riêng tư? –

+0

@ PeterA.Schneider Cũng đúng đối với 'thừa kế được bảo vệ', đối với' thừa kế riêng', sẽ là "các thành viên được bảo vệ của nó trở thành các thành viên riêng của lớp dẫn xuất". – songyuanyao

0

Khái niệm về khả năng truy cập của các thành viên trong lớp theo WORLD được áp dụng tại đây. WORLD chỉ có thể truy cập vào các thành viên public class bất kể chúng được tạo ra/bắt nguồn như thế nào.

xem xét ví dụ dưới đây:

class A 
{ 
    public: 
     int public_i; 
    protected: 
     int protected_i; 
    private: 
     int private_i; 

    public: 
     A() 
     { 
      public_i = 10; 
      protected_i = 20; 
      private_i = 30; 
     } 
}; 

class C : protected A 
{ 
    public: 
     void Access(void) 
     { 
      cout << public_i << endl; 
      cout << protected_i << endl; 
      //cout << private_i << endl; // <- Not Allowed b'coz its private here 
     } 
}; 
class D : private A 
{ 
    public: 
     void Access(void) 
     { 
      cout << public_i << endl; 
      cout << protected_i << endl; 
      //cout << private_i << endl; // <- Not Allowed b'coz its private here 
     } 
}; 
class B : public A 
{ 
    public: 
     void Access(D *pd) 
     { 
      cout << public_i << endl; 
      cout << protected_i << endl; 
      //cout << private_i << endl; // <- Not Allowed b'coz its private here 

      //pd is WORLD here 
      //cout << pd->public_i << endl; // <- Not Allowed b'coz its private here since private inheritance of A by D 
      //cout << pd->protected_i << endl; // <- Not Allowed b'coz its protected here 
      //cout << pd->private_i << endl; // <- Not Allowed b'coz its private here 
     } 
}; 


int main() 
{ 
    A objA; 
    cout << objA.public_i << endl; 
    //cout << objA.protected_i << endl; // <- Not Allowed b'coz its protected here 
    //cout << objA.private_i << endl; // <- Not Allowed b'coz its private here 

    B objB; 
    cout << objB.public_i << endl; 
    //cout << objB.protected_i << endl; // <- Not Allowed b'coz its protected here 
    //cout << objB.private_i << endl; // <- Not Allowed b'coz its private here 

    C objC; 
    //cout << objC.public_i << endl; // <- Not Allowed b'coz its protected here 
    //cout << objC.protected_i << endl; // <- Not Allowed b'coz its protected here 
    //cout << objC.private_i << endl; // <- Not Allowed b'coz its private here 

    D objD; 
    //cout << objD.public_i << endl; // <- Not Allowed b'coz its private here 
    //cout << objD.protected_i << endl; // <- Not Allowed b'coz its protected here 
    //cout << objD.private_i << endl; // <- Not Allowed b'coz its private here 

    //Outside class its all WORLD and WORLD can access only public members. 
    //Objects and Pointers are WORLD. 

    //Same thing is applicable when class members are accessed via pointers. 
    B *pobjB;  //pobjB is WORLD 
    cout << pobjB->public_i << endl; 
    //cout << pobjB->protected_i << endl; // <- Not Allowed b'coz its protected here 
    //cout << pobjB->private_i << endl; // <- Not Allowed b'coz its private here 

    objB.Access(&objD); 
    objC.Access(); 
    objD.Access(); 

    return 0; 
} 
Các vấn đề liên quan