2009-06-20 27 views
120

thể trùng lặp:
Forward declaration of nested types/classes in C++Làm cách nào để chuyển tiếp khai báo lớp bên trong?

Tôi có một lớp học như vậy ...

class Container { 
public: 
    class Iterator { 
     ... 
    }; 

    ... 
}; 

Ở những nơi khác, tôi muốn vượt qua một container :: Iterator bằng cách tham khảo, nhưng tôi không muốn bao gồm tệp tiêu đề. Nếu tôi cố gắng chuyển tiếp khai báo lớp, tôi sẽ nhận được các lỗi biên dịch.

class Container::Iterator; 

class Foo { 
    void Read(Container::Iterator& it); 
}; 

Biên dịch mã trên cho ...

test.h:3: error: ‘Iterator’ in class ‘Container’ does not name a type 
test.h:5: error: variable or field ‘Foo’ declared void 
test.h:5: error: incomplete type ‘Container’ used in nested name specifier 
test.h:5: error: ‘it’ was not declared in this scope 

Làm thế nào tôi có thể về phía trước tuyên bố lớp này vì vậy tôi không cần phải bao gồm các tập tin tiêu đề mà tuyên bố lớp Iterator?

Trả lời

102

Điều này không thể thực hiện được. Bạn không thể chuyển tiếp khai báo một cấu trúc lồng nhau bên ngoài vùng chứa. Bạn chỉ có thể chuyển tiếp khai báo trong vùng chứa.

Bạn sẽ cần phải làm một trong những cách sau

  • Làm cho lớp phi lồng nhau
  • Thay đổi trật tự khai của bạn để các lớp lồng nhau là hoàn toàn được xác định đầu tiên
  • Tạo một lớp cơ sở chung có thể được sử dụng cả trong hàm và được thực hiện bởi lớp lồng nhau.
+2

Lớp cơ sở chung là giải pháp được sử dụng nhiều nhất ở phần cuối của tôi. – Coyote

+0

Bạn có thể sử dụng bạn bè để giải quyết vấn đề này nếu muốn. –

+1

Lỗi: http: //en.cppreference.com/w/cpp/language/nested_types – Nikerboker

18

Tôi không tin rằng phía trước tuyên bố lớp bên trong của công trình trên một lớp đầy đủ (bởi vì không có định nghĩa lớp, không có cách nào để biết nếu có thực sự một lớp bên trong). Vì vậy, bạn sẽ phải bao gồm định nghĩa của container, với một lớp bên trong phía trước tuyên bố:

class Container { 
public: 
    class Iterator; 
}; 

Sau đó, trong một tiêu đề riêng biệt, thực hiện container :: Iterator:

class Container::Iterator { 
}; 

Sau đó #include chỉ tiêu đề vùng chứa (hoặc không lo lắng về việc khai báo trước và chỉ bao gồm cả hai)

+4

Câu trả lời hay, ngoại trừ phần trong ngoặc đơn đầu tiên. "Không có cách nào để biết nếu có thực sự là một lớp bên trong" không có ý nghĩa trong bối cảnh này và là nghi ngờ để được chính xác. Toàn bộ điểm của một khai báo chuyển tiếp là bạn đang nói với trình biên dịch rằng có một lớp (hoặc trong trường hợp này là một lớp bên trong). Đó là tuyên bố cụ thể của bạn sẽ được đúng như các lớp học bình thường và có nghĩa là bạn không thể chuyển tiếp tuyên bố bất cứ điều gì. – Aaron

1

Tôi biết không có cách nào để thực hiện chính xác những gì bạn muốn, nhưng đây là giải pháp thay thế nếu bạn sẵn sàng sử dụng mẫu:

// Foo.h 
struct Foo 
{ 
    export template<class T> void Read(T it); 
}; 

// Foo.cpp 
#include "Foo.h" 
#include "Container.h" 
/* 
struct Container 
{ 
    struct Inner { }; 
}; 
*/ 
export template<> 
    void Foo::Read<Container::Inner>(Container::Inner& it) 
{ 

} 

#include "Foo.h" 
int main() 
{ 
    Foo f; 
    Container::Inner i; 
    f.Read(i); // ok 
    f.Read(3); // error 
} 

Hy vọng rằng, thành ngữ này có thể là của một số sử dụng cho bạn (và hy vọng trình biên dịch của bạn là EDG-based và thực hiện xuất khẩu;)).

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