2015-12-13 26 views
16

tôi làm lớp này đơn giản, mà vẫn được chơi với tâm trí tôi:Tiếp cận lớp lồng nhau tin

class A { 
private: 
    class B {}; 

public: 
    B getB() { 
     return B(); 
    }; 
}; 

Tính đến C++ 03, lớp này biên dịch tốt, nhưng có chỉ là không đẹp tìm cách để gán kết quả của getB() cho một giá trị, theo nghĩa là:

A::B b = A().getB(); 

Không biên dịch.

tôi đã nhận nó bằng cách sử dụng một mẫu trung gian, theo cách này:

template <typename T> 
struct HideType { 
    typedef T type; 
}; 

HideType<A::B>::type b = A().getB(); 

Nhưng điều này có vẻ chỉ là khủng khiếp, cho nhiệm vụ này đơn giản nhận được một biến vế trái A :: B.

Điều này không còn đúng nữa kể từ C++ 11 hoặc ít nhất là không phải với gcc. Mã này vẫn là không hợp lệ:

A::B b = A().getB(); 

Nhưng đây là hợp lệ:

auto b = A().getB(); 

Có một lỗ hổng trong sự tôn trọng tiêu chuẩn để điều này?

+1

Có liên quan: http://stackoverflow.com/questions/13532784/why-can-i-use-auto-on-a-private-type – OMGtechy

+1

Tôi không thể nhận được ['HideType :: type b = .. .'] (http://ideone.com/jwsXhG) để biên dịch, bạn có thể hiển thị MCVE ở đâu không? Bạn có thể quan tâm đến [cấu trúc cướp] của litb (http://stackoverflow.com/questions/15110526/allowing-access-to-private-members) để thay thế. –

Trả lời

1

Thực tế tại sao A::B b = A().getB() không hoạt động vì B là thành viên riêng tư của lớp A. Nếu bạn đặt công khai thì mã của bạn sẽ biên dịch. Nó hoạt động với autoauto chỉ kiểm tra loại đối tượng được gán cho nó mà không cần gọi hàm tạo của đối tượng (giống như declval). Vì vậy, nó gán b với kiểu trả về là getB có trong lớp A. Bạn có thể thay đổi mã của bạn theo cách sau quá:

decltype(declval<A>().getB()) b = A().getB(); 

(Nếu declval là mới đối với bạn thì tôi phải nói với bạn rằng nó sẽ trở về một rvalue của kiểu trả về của hàm (ở đây getB mà trở lại loại là B) của một lớp (ở đây A) mà không cần gọi hàm tạo của lớp! (Tuy nhiên, điều này chỉ nên được sử dụng với các hàm như decltypesizeof.) Vì vậy, nó ngăn không cho việc tạo đối tượng lớp và sau đó sử dụng hàm của nó.)

Bây giờ theo tôi, tôi không nghĩ đây là một lỗ hổng trong tiêu chuẩn thay vì tôi cảm thấy vòng lặp lỗ đã được gỡ bỏ! Rõ ràng là từ mã của riêng bạn, hãy xem hàm getB. Làm thế nào là khó khăn để nhanh chóng một đối tượng của B bởi vì nó được định nghĩa trong tư nhân! Trong trường hợp này làm việc với B trở nên khó khăn. Ý tưởng đằng sau điều này là tên của loại (tức là B) trong lớp A là không thể tiếp cận nhưng loại vẫn có thể sử dụng được đó là lý do tại sao bạn có thể nhận được một đối tượng của B.Bạn có thể hiểu việc sử dụng auto nếu bạn hiểu đoạn code mẫu này: -

#include <iostream> 
#include <type_traits> // for std::is_same 
using namespace std; 
class A 
{ 
    class B 
    {}; 
    public: 
    B getB() 
    { 
     return B(); 
    } 
}; 
template<typename T> 
void check (T b) 
{ 
    cout<<boolalpha; 
    is_same<decltype(declval<A>().getB()), T> x; // checks if T & B are of same type 
    cout<<x.value<<'\n'; 
} 
int main() 
{ 
    A obj; 
    check (obj.getB()); 
    return 0; 
} 

Output: -

true 

Khi template có thể xác định B, do đó auto quá xác định B.

+0

"* Nó hoạt động với' tự động' bởi vì đó là những gì 'tự động' là !!!! Nó sẽ chỉ kiểm tra xem loại được gán cho nó có hợp lệ hay không *" Đây là tất cả vô nghĩa. – ildjarn

+0

Và 'decltype' là C++ 11, giống như' auto', vậy điểm đề xuất là gì? –

+0

Thats chỉ là một thông tin bổ sung để báo cho OP biết rằng bạn có thể truy cập đối tượng 'B' mà không cần sử dụng' auto'. – Anwesha

9

Từ Standard, khoản 11 (Thành viên kiểm soát truy cập):

Một thành viên của một lớp có thể
- tư nhân; nghĩa là, chỉ có thể sử dụng tên của các thành viên và bạn bè của lớp mà nó được khai báo.
- được bảo vệ; có nghĩa là, tên chỉ có thể được sử dụng bởi các thành viên và bạn bè của lớp học trong đó được tuyên bố là , bởi các lớp học có nguồn gốc từ lớp đó và bởi bạn bè của họ (xem 11.4).
- công khai; nghĩa là, tên của bạn có thể được sử dụng ở mọi nơi mà không bị hạn chế truy cập.

Vì vậy, kiểm soát truy cập được áp dụng cho tên.

Trong

auto b = A().getB(); 

bạn không sử dụng tên tư nhân, do đó nó là hợp pháp, theo tiêu chuẩn

0

Dường như, đã có như vậy một khiếm khuyết trong một dự thảo tiêu chuẩn, nhưng nó đã được được sửa bởi WP 1170.

Có thể, có lỗi trình biên dịch. Tuyên bố auto b = A().getB(); liên quan đến việc khấu trừ đối số mẫu cho autoloại-specifier, do đó, theo tiêu chuẩn C++ 11, nó sẽ bị hỏng, vì loại khấu trừ đó không thành công.

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