2012-07-10 50 views
18

Tôi tương đối mới với C++, và tôi đã nhìn rất nhiều cho một câu trả lời cho điều này nhưng tôi không bao giờ có một câu trả lời thỏa mãn.Lớp bên trong truy cập lớp bên ngoài

Giả sử tôi có cấu trúc được gọi là FSM. Cuối cùng trong mã của tôi, có thể tạo nhiều phiên bản FSM. Một trong những thuộc tính của FSMint X không phải là tĩnh, mỗi trường hợp của FSM phải có giá trị riêng cho X.

Bây giờ, một trong những thuộc tính FSM 's là một cấu trúc submachine mà cần phải đọc giá trị của X như thế này:

struct FSM 
{ 
    public: 
    int x; 

    int getX(){return x;} 

    struct submachine 
    { 
     void onentry() {int g = getX();}; 
    }; 
}; 

này cung cấp cho các lỗi sau:

Error: 'FSM::getX' : illegal call of non-static member function

Câu hỏi của tôi là , submachine là thành viên của FSM, vì vậy không nên truy cập vào các phiên bản cục bộ của tất cả các thuộc tính của FSM? Và nếu không, khi chúng tôi tạo một thể hiện của FSM, chúng tôi sẽ không tạo một phiên bản của tất cả các thành viên của nó, tức là submachine? Và nếu có, thì tại sao chúng ta cần phải tạo ra một đối tượng mà nhu cầu onentry()?

Tôi giả định trình biên dịch là chính xác, vì vậy tôi cũng muốn biết nếu có cách nào để thực hiện công việc này. LƯU Ý: Thật không may, các trường hợp của các cấu trúc bên trong (submachine) được khởi tạo khi một sự kiện được gọi và do đó tôi chỉ có thể xác định loại và không thể khởi tạo các đối tượng cho chúng trong FSM.

Trả lời

34

my question is, submachine is a member of FSM, so it should have access to local instances of all the attributes of FSM, no?

No. Không giống như Java, các đối tượng lớp bên trong không có tham chiếu ngầm định đối tượng bên ngoài.

wouldn't we be creating an intance of all its members i.e. submachine?

submachine là một loại , không phải là một biến thành viên. Nếu bạn muốn có một biến thành viên, bạn sẽ phải làm một cái gì đó như thế này:

struct FSM { 
    struct submachine { 
     ... 
    }; 

    submachine sm; // Member variable of type submchine 
}; 

Và nếu bạn muốn sm để "nhìn thấy" đối tượng cha của nó, bạn sẽ cần phải vượt qua nó một cách rõ ràng:

struct FSM { 
    struct submachine { 
     FSM &parent; // Reference to parent 
     submachine(FSM &f) : parent(f) {} // Initialise reference in constructor 
    }; 

    submachine sm; 

    FSM() : sm(*this) {} // Pass reference to ourself when initialising sm 
}; 

Lưu ý rằng nguyên tắc tương tự áp dụng cho các trường hợp submachine không phải là biến thành viên. Nếu bạn muốn họ có thể truy cập một phiên bản FSM, bạn sẽ cần phải chuyển một tham chiếu đến một.

Cũng lưu ý rằng bạn có thể sử dụng con trỏ thay vì tham chiếu. Trong thực tế, một con trỏ cung cấp sự linh hoạt lớn hơn trong nhiều trường hợp.

+0

nếu có cách nào tôi hoàn thành những gì tôi muốn thực hiện? – Kam

+2

Downvoter: quan tâm để chia sẻ? –

+0

(Xin lỗi vì sự chậm trễ, đã tìm thấy liên kết). Các lớp lồng nhau là các thành viên và có thể truy cập lớp bên ngoài giống như bất kỳ thành viên nào khác, xem [DR 45] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45), một phần của tiêu chuẩn từ năm 2003 –

2

Lưu ý rằng việc khai báo struct submachine chỉ xác định loại; nó không thực sự tạo ra một trường trong lớp của kiểu đó.

Bạn sẽ cần một trong các cách sau:

struct submachine mysub; // creates a field after the class is defined 

hoặc

struct submachine 
{ 
    . . . 
} mysub; // creates the field "mysub" also, as the structure is being defined 

Điều này làm cho mysub lĩnh vực này, và sau đó bạn truy cập vào nó trong cùng một cách mà bạn muốn truy cập x.

Định nghĩa của submachine cần bao gồm một cụ FSM (ví dụ một lĩnh vực con trỏ FSM*, và có lẽ một constructor như submachine(FSM* fsm): fsm_(fsm) {} để khởi tạo nó) để bạn có thể nói fsm_->getX() để truy cập một giá trị nhất định X.

+0

Thật không may, các cá thể của cấu trúc bên trong được khai báo thời gian chạy (sự kiện) và do đó Tôi chỉ có thể xác định loại, và không instanciate đối tượng cho họ. – Kam

+2

Bạn vẫn không thể thực hiện 'int g = getX();' không có đối tượng 'FSM'. Làm thế nào để trả lời câu hỏi này? –

1

Tôi chỉ đoán xem bạn muốn làm gì, nhưng nếu dự đoán của tôi là chính xác, bạn có thể nghĩ về điều gì đó như dưới đây.

struct FSM_Base { 
    int x; 

    struct submachine1; 
    struct submachine2; 

    FSM_Base() : x(0) {} 
    virtual ~FSM_Base() {} 
}; 

struct FSM_Base::submachine1 : virtual public FSM_Base { 
    void oneentry() { int g = x; } 
}; 

struct FSM_Base::submachine2 : virtual public FSM_Base { 
    void oneentry() { int g = x; } 
}; 

struct FSM : public FSM_Base::submachine1, 
      public FSM_Base::submachine2 { 
    FSM_Base::submachine1 * sub1() { return this; } 
    FSM_Base::submachine2 * sub2() { return this; } 
}; 
3

xem xét rằng trong ví dụ của bạn, tôi về mặt pháp lý có thể viết một hàm tự do

void foo() 
{ 
    FSM::submachine sub; 
    sub.onentry(); 
} 

nơi có không dụ FSM rằng sub có thể tham khảo.

Hoặc, như Oli nói, có cửa hàng submachine đối tượng một tham chiếu đến đối tượng cha FSM của nó, hoặc có lẽ chỉ cần vượt qua giá trị của x trực tiếp vào onentry (nó không phải là rõ ràng như thế nào nó được gọi).


Từ xem nhanh Boost.MSM docs Tôi tìm thấy ghi chú này trên non-default-constructed submachines.

Thật xấu xí, tôi không hiểu phụ trợ đủ để diễn giải nó ở đây và mã theo nghĩa đen sẽ không có đủ ý nghĩa để tách biệt.

Đoạn mã ví dụ liên kết từ đó cũng cho thấy phương pháp nhập của tiểu liên với chữ ký sau đây:

template <class Event,class FSM> void on_entry(Event const&,FSM&); 

nếu đó là chính xác, bạn có thể lưu trữ một con trỏ đến bạn máy nhà nước ngoài on_entry, hoặc trích xuất các giá trị của x đó và ghi lại nó trong tiểu liên.

+0

Cảm ơn bạn! Đây là những gì tôi đang tìm kiếm, bây giờ tôi thực sự có được nó. bài đăng này với bài viết của OLI đã làm cho tôi. Tôi ước tôi có thể chấp nhận cả hai câu trả lời. – Kam

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