2010-01-26 27 views
24

Hãy xem xét đoạn mã sau:Thay đổi chức năng Chế độ truy cập trong lớp có nguồn gốc

struct Base 
{ 
    virtual ~Base() {} 

    virtual void Foo() const = 0; // Public 
}; 

class Child : public Base 
{ 
    virtual void Foo() const {} // Private 
}; 

int main() 
{ 
    Child child; 

    child.Foo(); // Won't work. Foo is private in this context. 

    static_cast<Base&> (child).Foo(); // Okay. Foo is public in this context. 
} 

là hợp lệ trong C++ này? "Điều này" đang thay đổi chế độ truy cập của hàm ảo trong lớp dẫn xuất.

+1

... Đã biên dịch và chạy chưa? – AndyG

+17

@SauceMaster, Đó không phải là một dấu hiệu rất tốt cho dù mã là hợp pháp trong C + +. Có rất nhiều tải và mã C++ sẽ biên dịch và chạy, nhưng vẫn gọi hành vi không xác định. Thay đổi trình biên dịch, cờ biên dịch, phiên bản trình biên dịch và sự bùng nổ, nó ngừng hoạt động. – Glen

+0

Đồng ý với Glen. Đó là lý do tôi hỏi ở đây. – hlx236sk

Trả lời

11

Có, thay đổi chế độ truy cập trong các lớp học có nguồn gốc hợp pháp.

Đây là tương tự ở dạng nhưng khác nhau trong ý định đến Non-Virtual Interface thành ngữ. Một số lý do được đưa ra here:

Điểm là các hàm ảo tồn tại để cho phép tùy chỉnh; trừ khi họ cũng cần phải được gọi trực tiếp từ bên trong mã lớp học có nguồn gốc, không cần phải bao giờ làm cho họ bất cứ điều gì nhưng riêng tư.

Là tại sao bạn thực sự sẽ làm một cái gì đó public trong cơ sở nhưng private trong nguồn gốc mà không private hoặc protected thừa kế là ngoài tôi.

+0

Tốt. Tôi đã sử dụng cách tiếp cận này cho một khía cạnh định dạng nhưng không chắc chắn nếu điều này là hợp pháp. Cảm ơn bạn! – hlx236sk

+4

Điều này khá trái ngược với NVI: Hàm lớp cơ sở là public + virtual, nhưng trong NVI nó là private + virtual và hàm public gọi nó là nonvirtual. –

+0

@litb, Ah, whups. Vâng, tôi đã sửa văn bản kể từ khi tôi bỏ lỡ cơ sở ảo công khai, có nguồn gốc riêng ảo. – MSN

5

Nó hoàn toàn hợp pháp C++. Bạn chỉ đơn giản là định nghĩa một phương thức mới trong lớp Child.

Bây giờ nó làm những gì bạn muốn nó để làm, đó là một câu hỏi khác. Tôi tin rằng chế độ truy cập không phải là một phần của chữ ký phương thức, có nghĩa là gọi phương thức ảo Foo của Base cuối cùng gọi phương thức Foo của Child.

Vì vậy, đây là kết luận: nó là hợp pháp C++ và nó hoạt động theo cách bạn mong muốn.

Tôi không tính đến dòng child.Foo(); không thể hoạt động vì không nghi ngờ gì là đang cố gắng truy cập phương thức Foo() riêng của Trẻ em.

4

Dường như biên dịch và gọi đúng phương pháp.

Hãy nhớ rằng specifiers truy cập đang có để giúp một lập trình viên có kỷ luật, chứ không phải để ngăn chặn mọi nỗ lực để phá vỡ nó bằng mọi giá.

Trong trường hợp cụ thể này, Trẻ không có doanh nghiệp làm cho chức năng ảo bị ghi đè riêng tư: không phải là nó phải triển khai giao diện công khai của Base, vì vậy mối quan hệ "là-a" có được không? (Nếu bạn không sử dụng thừa kế công cộng, có nghĩa là "trẻ em là một cơ sở", lừa của bạn sẽ không hoạt động.)

+1

"Hãy nhớ rằng các thông số truy cập có sẵn để giúp lập trình viên có kỷ luật, không để ngăn chặn mọi nỗ lực phá vỡ nó bằng mọi giá." là một điểm tuyệt vời – austinmarton

19

này là hợp pháp C++, §11.6/1 nói:

Tiếp cận được kiểm tra tại các điểm gọi sử dụng các loại biểu thức sử dụng để biểu thị các đối tượng mà các chức năng thành viên được gọi là (B * trong ví dụ ở trên). Khả năng tiếp cận của hàm thành viên trong lớp, trong đó nó đã được xác định (D trong ví dụ ở trên) là nói chung không được biết đến.

Như bạn đã nói, Child::Foo() là như vậy, vẫn truy cập qua lớp cơ sở, đó là trong nhiều trường hợp không mong muốn:

Child* c = new Child; 
Base* b = c; 
c->Foo(); // doesn't work, Child::Foo() is private 
b->Foo(); // works, calls Child::Foo() 

Về cơ bản, việc kê khai bạn tham khảo trong biểu thức mệnh lệnh chế độ truy cập - nhưng các chức năng ảo làm suy yếu rằng một hàm khác thì hàm có tên thực sự có thể được gọi.

+0

Vậy việc thực thi 'Foo' nào được thực thi trong' b-> Foo() '? 'Child :: Foo' hoặc' Base :: Foo'? Nếu 'Child :: Foo' này ngắt điều khiển truy cập trong lớp dẫn xuất. – ThomasMcLeod

+1

@ThomasMcLeod: Nhận xét trong cùng dòng nói rằng;) –

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