2010-07-28 26 views
16

Tôi có hai lớp, Foo<T>Bar<T>, có nguồn gốc từ Base. Mỗi ghi đè phương thức virtual Base* convert(ID) const, trong đó ID là phiên bản của một loại xác định duy nhất một phiên âm cụ thể của Foo hoặc Bar (giả vờ là enum). Vấn đề là Foo::convert() cần phải có thể trả lại phiên bản Bar và tương tự như vậy Bar::convert() cần phải có thể khởi tạo Foo. Vì chúng là cả hai mẫu, điều này dẫn đến sự phụ thuộc vòng tròn giữa Foo.hBar.h. Làm cách nào để giải quyết vấn đề này?Giải quyết sự phụ thuộc thông tư giữa các lớp mẫu

Edit: Một tờ khai phía trước không hoạt động vì việc thực hiện mỗi phương pháp cần constructor của lớp khác:

Foo.h:

#include <Base.h> 

template<class T> class Bar; 

template<class T> 
class Foo : public Base { ... }; 

template<class T> 
Base* Foo<T>::convert(ID id) const { 

    if (id == BAR_INT) 
     return new Bar<int>(value); // Error. 

    ... 

} 

Bar.h:

#include <Base.h> 

template<class T> class Foo; 

template<class T> 
class Bar : public Base { ... }; 

template<class T> 
Base* Bar<T>::convert(ID id) const { 

    if (id == FOO_FLOAT) 
     return new Foo<float>(value); // Error. 

    ... 

} 

Lỗi là, một cách tự nhiên, "sử dụng không hợp lệ loại không đầy đủ".

+0

phụ thuộc Cyclic hiếm khi một ý tưởng tốt. Hãy thử cấu trúc lại nó để phụ thuộc bị hỏng. Ý tưởng đầu tiên là chuyển phương thức 'convert' thành một hàm miễn phí phụ thuộc vào cả' Bar' và 'Foo' ... –

Trả lời

18

Những gì bạn cần làm là tách biệt các khai báo lớp khỏi quá trình triển khai. Vì vậy, một cái gì đó như

template <class T> class Foo : public Base 
{ 
    public: 
    Base* convert(ID) const; 
} 

template <class T> class Bar : public Base 
{ 
    public: 
    Base* convert(ID) const; 
} 

template <class T> Base* Foo<T>::convert(ID) const {return new Bar<T>;} 
template <class T> Base* Bar<T>::convert(ID) const {return new Foo<T>;} 

Bằng cách này, bạn có định nghĩa lớp hoàn chỉnh khi các hàm được xác định.

+0

Điều này nghe có vẻ đầy hứa hẹn. Tôi không quan tâm đến nó. –

+0

Tất cả các thiết lập! Cảm ơn rất nhiều. –

+0

Hãy cho tôi một vài lần đọc để tìm ra những gì bạn đang làm với câu trả lời này - bằng cách kết hợp hai tiêu đề với nhau và đặt các định nghĩa hàm bên dưới cả hai khai báo lớp bạn tránh các vấn đề - suy nghĩ tốt. Đã giúp tôi quá –

9

(Đã cập nhật) Bạn sẽ có thể xử lý giống như với các lớp không phải mẫu. Viết Bar.h của bạn như thế này. (Và tương tự cho foo.h)

#if !defined(BAR_H_INCLUDED) 
#define BAR_H_INCLUDED 

template <class T> 
class Foo; 

template <class T> 
class Bar 
{ 
    /// Declarations, no implementations. 
}  

#include "Foo.h" 

template <class T> 
Base* Bar<T>::Convert() { /* implementation here... */ } 
#endif 
+0

Không có xúc xắc. Các lớp không thể được khai báo trước bởi vì tôi cần sử dụng các thành viên của chúng, hoặc ít nhất là hàm tạo, để thực hiện chuyển đổi. Tôi nhận được "sử dụng không hợp lệ loại không đầy đủ". –

+0

@Jon: Xem bài đăng cập nhật. –

+0

Giải pháp tôi tự làm ra từ câu trả lời của KeithB tương tự như thế này, nhưng tôi không nghĩ điều này thực sự biên dịch bởi vì 'Foo.h' và' Bar.h' vẫn cần phải bao gồm nhau, vì vậy người ta sẽ trống rỗng -handand. –

11

Bạn nên sử dụng tờ khai chuyển tiếp lớp mẫu ở một trong hai tiêu đề

template <class T> 
class X; 

là hoàn toàn tốt lớp mẫu tờ khai phía trước.

7

Câu trả lời của James Curran là một ơn trời. Nói chung, ý tưởng của James là hạn chế việc bao gồm các tệp tiêu đề bắt buộc cho đến thời điểm các thành viên ('khai báo) đến từ các tệp tiêu đề được bao gồm là cần thiết. Như một ví dụ:

t1.hh

#ifndef S_SIGNATURE 
#define S_SIGNATURE 

struct G; // forward declaration 

template<typename T> 
struct S { 
    void s_method(G &); 
}; 

#include "t2.hh" // now we only need G's member declarations 

template<typename T> 
void S<T>::s_method(G&g) { g.g_method(*this); } 

#endif 

t2.hh

#ifndef G_SIGNATURE 
#define G_SIGNATURE 

template<typename T> 
struct S; // forward declaration 

struct G { 
    template<typename T> 
    void g_method(S<T>&); 
}; 

#include "t1.hh" // now we only need S' member declarations 

template<typename T> 
void G::g_method(S<T>& s) { s.s_method(*this); } 

#endif 

t.cc

#include "t1.hh" 
#include "t2.hh" 

S<int> s; 
G g; 

int main(int argc,char**argv) { 
    g.g_method(s); // instantiation of G::g_method<int>(S<int>&) 
} 
+0

Tôi chỉ cần đưa ra một câu trả lời bắt đầu "Câu trả lời của James Curran là một ơn trời" –

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