2014-09-20 11 views
7

Tôi nhầm lẫn về việc kiểm tra các bộ định danh truy cập tĩnh hoặc động. Người ta nói rằng truy cập specifiers không được kiểm tra động. Điều đó nghĩa là gì ?Cần hiểu câu lệnh "Khả năng truy cập được kiểm tra tĩnh và không tự động trong C++"

Ví dụ này được lấy từ posts khác nhau trên SO. Hãy xem xét ví dụ này

Ví dụ A:

class Base 
{ 
public: 
    virtual void Message() = 0; 
}; 

class Intermediate : public Base 
{ 
    //Is Message method virtual here too ? is it private or public ? 
}; 

class Final : public Intermediate { 
    void Message() { 
     cout << "Hello World!" << endl; 
    } 
}; 

Final final; 

Bây giờ giả sử tôi làm điều gì đó như

Final* finalPtr = &final; 
finalPtr->Message(); 

Công việc sẽ không ở trên này và sự hiểu biết của tôi là trong lớp học cuối cùng Phương pháp tin nhắn là tư nhân. Đúng không ? Nếu vậy tại sao điều này làm việc? phương thức trong

Intermediate* finalPtr = &final; // or Base* finalPtr = &final; 
    finalPtr->Message(); 

Lý do tại sao mã trên là làm việc vì con trỏ lớp cơ sở được khởi tạo với lớp dẫn xuất. Nếu vậy tại sao cuộc gọi đến Message() hoạt động. Các bài viết trên SO nói rằng kể từ khi thừa kế là công khai do đó nó sẽ được thừa hưởng như là chức năng công cộng? mặt khác, bản thân hàm trong lớp có đặc tả truy cập riêng (vì theo mặc định là hàm riêng của nó trong một lớp). Tôi bối rối ở đây và tôi sẽ đánh giá cao nếu ai đó có thể làm rõ điều này. Nó sẽ là chính xác để nói rằng nếu một lớp cơ sở được khởi tạo với một lớp dẫn xuất. Sau đó, các specifier truy cập của phương thức lớp cơ sở được ưu tiên hơn các specifier truy cập của lớp dẫn xuất?

Cập nhật:

Ngoài ra tôi nhận thấy rằng nếu tôi thay đổi mã IntermediateFinal như sau

class Intermediate : public Base 
{ 
public: //Incase this public was absent then the following example wont work 
    void Message() { 
     cout << "Hello World! Intermediate" << endl; 
    } 
}; 

class Final : public Intermediate { 
    void Message() { 
     cout << "Hello World! final" << endl; 
    } 
}; 

và sử dụng nó như thế

Intermediate* i = new Final(); 
    i->Message(); 

Sau đó inorder để có được đầu ra "Hello World! final" nó là cần thiết để đánh dấu giao diện phương thức công khai. Tại sao vậy ? Phương thức Message được kế thừa là công khai. Tại sao tôi cần phải đánh dấu nó là công khai ngay bây giờ?

+1

Bạn nên liên kết các bài đăng khác. Bởi vì bạn đã không, bạn sẽ nhận được lời giải thích chính xác mà bạn không hiểu. –

+0

chỉ cần thêm liên kết – Rajeshwar

Trả lời

8

Những tuyên bố trong báo giá của bạn có nghĩa là việc kiểm tra quyền truy cập dựa trên kiểu tĩnh của biểu thức bạn đã áp dụng . vận hành (hoặc -> tương đương với * với .).

Nếu T là một loại sau đó cho:

T *t = something....; 
t->foo(); 

các kiểm tra quyền truy cập là cho tên T::foo, ngay cả khi con trỏ thực sự trỏ tới một đối tượng của một lớp học có nguồn gốc từ foo.

Một cách khác để nói đây là kiểm tra quyền truy cập phải có thể được thực hiện tại thời gian biên dịch. Không có thứ như "lỗi truy cập thời gian chạy".


Trong ví dụ mã của bạn bạn có:

Intermediate* finalPtr = something.....; 
finalPtr->Message(); 

Tên được nhìn lên là Intermediate::Message. Lớp IntermediateMessage là một hàm public, vì vậy việc kiểm tra này thành công.

Nhận xét của bạn cho thấy có thể bạn không chắc chắn về khả năng truy cập của các hàm được kế thừa. Có ba loại dẫn xuất (hơi gây nhầm lẫn, chúng cũng được gọi là private, protected, public). public thừa kế là phổ biến nhất; nó có nghĩa là public thành viên của lớp cơ sở cũng là public thành viên của lớp dẫn xuất.

Kể từ Base::Message là công khai và Intermediate được công khai bắt nguồn từ Base, sau đó Intermediate::Message cũng được công khai.

Để rõ ràng, đó là tên có quyền truy cập. Base::MessageIntermediate::Message là hai tên khác nhau, nhưng cả hai đều có cùng tên.

Trong Final, nó khai báo tên Message trong phần private, điều này có nghĩa là Final::Message là riêng tư. Mặc dù thừa kế là công khai, khai báo mới có tên Final::Message đổ bóng cái được thừa hưởng từ Cơ sở.


Để trả lời "cập nhật". Khi mã là:

class Intermediate : public Base 
{ 
public: //Incase this public was absent then the following example wont work 
    void Message() { 
     cout << "Hello World! Intermediate" << endl; 
    } 
}; 

bạn đã khai báo là Intermediate::Message là công khai. Do đó bạn có thể gọi hàm thông qua một con trỏ kiểu Intermediate *. Đó là những gì "công cộng" có nghĩa là. Nếu bạn làm cho nó private thì bạn không thể gọi nó.

Tôi không biết ý của bạn là gì "Thông báo phương pháp được kế thừa là công khai. Tại sao tôi cần đánh dấu nó là công khai ngay bây giờ". Khi bạn viết void Message() bên trong class Intermediate, nó khai báo một hàm mới. Tên của hàm đó đổ bóng tên được thừa hưởng.

+0

Sau đó, sẽ đúng khi nói rằng nếu một lớp cơ sở được khởi tạo với một lớp dẫn xuất. Sau đó, các specifier truy cập của phương thức lớp cơ sở được ưu tiên hơn các specifier truy cập của lớp dẫn xuất? – Rajeshwar

+0

Không có điều gì như "lớp cơ sở được khởi tạo với một lớp dẫn xuất", do đó sẽ không chính xác. –

+0

@Rajeshwar cập nhật –

4

Việc kiểm tra này chỉ được thực hiện vào thời gian biên dịch.

Bạn đã đặt Message() ở chế độ chung kết để có thể gọi từ cuối cùng.

Lớp Trung cấp không có kiến ​​thức về cách Thông báo được xác định trong lớp Cuối cùng.

+0

Sau đó, điều này sẽ chính xác? nếu một lớp cơ sở được khởi tạo với một lớp dẫn xuất. Sau đó, các specifier truy cập của phương thức lớp cơ sở được ưu tiên hơn các specifier truy cập của lớp dẫn xuất? – Rajeshwar

+0

@Rajeshwar Nếu bạn có một con trỏ đến lớp cơ sở, bạn chỉ có thể sử dụng giao diện lớp cơ sở, trình biên dịch không có kiến ​​thức về những gì con trỏ thực sự trỏ đến. – molbdnilo

+0

Cái gì?Ông đã nhắn tin() riêng trong lớp Final, vì vậy nó không thể được gọi thông qua một tham chiếu/con trỏ đến Final. Điều này được kiểm tra (tĩnh) tại thời gian biên dịch, vì vậy ngay cả khi thời gian chạy (loại động) của đối tượng là Cuối cùng, chức năng vẫn có thể truy cập. –

1

Để làm cho câu trả lời của Matt McNabb ngắn hơn. nếu bạn không chỉ định quyền truy cập của chức năng, tính năng này ở chế độ riêng tư. Giống như Final :: Message

có thể cho một lớp dẫn xuất để giảm khả năng truy cập của lớp cha. Điều này hữu ích trong một số trường hợp (như chặn các nhà xây dựng mặc định/sao chép, v.v.)

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