2010-02-22 51 views
6

Mã sau đây cung cấp lỗi biên dịch cho void b() { m = &A::a; }; cho biết rằng A::a() được bảo vệ. (Nó là gì - nhưng đó không phải là vấn đề)
Tuy nhiên trình biên dịch không quan tâm khi tôi viết B::a(). Mặc dù cả hai có nghĩa là cùng tôi muốn A::a() vì nó khẳng định rằng explicitely a() được định nghĩa trong A.Tại sao không thể lưu trữ một con trỏ hàm của một lớp cơ sở?

Vì vậy lý do tại sao A::a() cấm là gì?
EDIT
Có thể ai đó có thể tìm thấy ví dụ có thể gặp sự cố nếu A::a() được phép trong B::b(). Nếu có ví dụ như vậy, tôi sẽ đánh dấu nó là câu trả lời cho câu hỏi.
/EDIT

#include <iostream> 
#include <iomanip> 
#include <string> 
#include <cstdio> 

class A { 
protected: 
    void a(){ std::cout << "A::a()" << std::endl; }; 
}; 

typedef void (A::*f)(); 
class B : public A { 
public: 
    void b() { m = &A::a; }; // wont compile 
    // void b() { m = &B::a; }; // works fine 
    void c() { (this->*m)(); }; 
protected: 
    f m; 
}; 

int main(){ 
    B b; 
    b.b(); 
    b.c(); 
} 

// compile with 
// g++ -Wall main.cpp -o main 

Giải thích về các mã:
Trong B Tôi muốn để lưu trữ một con trỏ hàm đến một phương pháp A để có thể gọi đó là sau này trong B::c(). Và vâng, điều này cũng xảy ra trong cuộc sống thực. :-)

+0

Vui ... xảy ra cả với 'gcc-3.4.2' và 'gcc-4.3.2' –

+0

có thể liên quan http://stackoverflow.com/questions/477829/cannot-call-base-class-protected-functions/477868#477868 – josefx

Trả lời

1

Lý do nên tương tự như lý do tại sao bạn không thể làm điều này trong B hoặc:

class B: public A 
{ 
    //... 
    void foo(A& x) { 
     x.a(); //error 
    } 

    void foo(B& x) { 
     x.a(); //OK 
    } 
}; 

Đó bảo vệ không có nghĩa là B có thể truy cập vào một phần của bất kỳ lớp học miễn nó là A/có nguồn gốc từ A. Nội dung được bảo vệ chỉ khả dụng cho trường hợp này và các trường hợp khác của B.

2

Vì nếu không, thế giới bên ngoài có thể tìm thấy thành viên được bảo vệ này: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11174.

Xem thêm http://gcc.gnu.org/ml/gcc-patches/2004-06/msg00610.html.

+0

Hmm, trong sự thiếu hiểu biết của tôi, tôi vẫn không thể thấy tại sao nó là cần thiết. Con trỏ hàm và do đó phương thức này vẫn được bảo vệ trong B. Vì vậy, nó không thể truy cập từ bên ngoài và nếu nó là như vậy thì 'B :: b()' hoặc tôi đang thiếu điểm hoàn toàn? – Pascal

+0

@ tuner07, bảo vệ truy cập được xác định bởi loại tĩnh của biểu thức. Ngữ cảnh thực tế trong đó bạn lấy con trỏ hàm không đi vào. –

+0

@gf Nếu bảo vệ truy cập được xác định bởi kiểu tĩnh của biểu thức, bạn không nên gọi 'A :: a() 'ở bất kỳ đâu trong B. Nhưng điều đó là có thể. Vì vậy, quy tắc chỉ áp dụng cho trường hợp một hàm được lưu trữ vào một con trỏ hàm. Tôi vẫn không thể thấy lý do tại sao 'A :: a()' phải được trình biên dịch ngăn chặn. – Pascal

0

Bạn cố gắng truy cập thành viên được bảo vệ thông qua không gian tên chung (A :: a is :: A :: a here), sử dụng B :: A :: a thay thế.

+0

điều này vẫn không hoạt động. ít nhất là với gcc-3.4.4. – Pascal

Các vấn đề liên quan