2010-07-28 16 views
16

के बीच एक परिपत्र निर्भरता को हल करना मेरे पास दो वर्ग, Foo<T> और Bar<T> हैं, जो Base से व्युत्पन्न हैं। प्रत्येक virtual Base* convert(ID) const विधि को ओवरराइड करता है, जहां ID एक प्रकार का उदाहरण है जो विशिष्ट रूप से Foo या Bar (विशेष रूप से enum) का एक विशेष तत्काल पहचानता है। समस्या यह है कि Foo::convert() को Bar उदाहरण वापस करने में सक्षम होना आवश्यक है, और इसी प्रकार Bar::convert() को Foo को तुरंत चालू करने में सक्षम होना आवश्यक है। चूंकि वे दोनों टेम्पलेट्स हैं, इसलिए यह Foo.h और Bar.h के बीच एक परिपत्र निर्भरता में परिणाम देता है। मैं इसका कैसे समाधान करूं?टेम्पलेट क्लासेस

संपादित करें: एक आगे घोषणा काम नहीं करता है, क्योंकि प्रत्येक विधि के क्रियान्वयन अन्य वर्ग के निर्माता की जरूरत है:

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. 

    ... 

} 

त्रुटि, स्वाभाविक रूप से, "अपूर्ण प्रकार का अमान्य उपयोग" है।

+0

चक्रीय निर्भरता शायद ही कभी एक अच्छा विचार कर रहे हैं। इसे पुन: सक्रिय करने का प्रयास करें ताकि निर्भरता टूट गई हो। पहला विचार 'कन्वर्ट' विधि को एक फ्री फ़ंक्शन में ले जायेगा जो 'बार' और 'फू' दोनों पर निर्भर करता है ... –

उत्तर

18

आपको क्या करने की आवश्यकता है कार्यान्वयन से कक्षा घोषणाओं को अलग करना है। तो

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>;} 

इस तरह, फ़ंक्शन परिभाषित होने पर आपके पास पूर्ण श्रेणी परिभाषाएं हैं।

+0

यह वादा करता है। मैं इसके साथ झुका रहा हूँ। –

+0

सभी सेट! बहुत बहुत धन्यवाद। –

+0

मुझे इस जवाब के साथ क्या कर रहे हैं, यह जानने के लिए दो पाठ पढ़े - दोनों शीर्षकों को एक साथ विलय करके और कक्षा घोषणाओं के नीचे फ़ंक्शन परिभाषाओं को डालने से आप समस्याओं से बचें - अच्छी सोच। मुझे भी मदद मिली –

9

(अपडेटेड) आपको इसे गैर-टेम्पलेट कक्षाओं के साथ संभालने में सक्षम होना चाहिए। इस तरह अपना बारह लिखें। (और 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

कोई पासा नहीं। कक्षाओं को आगे घोषित नहीं किया जा सकता है क्योंकि रूपांतरण करने के लिए मुझे अपने सदस्यों, या कम से कम कन्स्ट्रक्टर का उपयोग करने की आवश्यकता है। मुझे अपेक्षित "अपूर्ण प्रकार का अमान्य उपयोग" मिलता है। –

+0

@ जोन: अद्यतन पोस्ट देखें। –

+0

समाधान मैं KeithB के जवाब से अपने आप को बाहर काम किया इस के समान है, लेकिन मुझे नहीं लगता यह वास्तव में संकलित है क्योंकि 'Foo.h' और' Bar.h' अभी भी, एक दूसरे को शामिल करने की जरूरत है ताकि एक अप खाली आ जाएगा -handed। –

11

आप या तो हेडर

template <class T> 
class X; 

पूरी तरह से अच्छा टेम्पलेट वर्ग आगे घोषणा है में टेम्पलेट वर्ग आगे घोषणाओं का उपयोग करना चाहिए।

7

जेम्स Curran का जवाब एक देवता है। आम तौर पर, जेम्स का विचार आवश्यक हेडर फाइलों को शामिल करना प्रतिबंधित है जब तक सदस्यों ('घोषणाएं) शामिल हेडर फ़ाइलों से आने की आवश्यकता नहीं होती है। एक उदाहरण के रूप:

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

मुझे बस एक उत्तर उभारा था जो शुरू होता है "जेम्स Curran का जवाब एक देवता है" –

संबंधित मुद्दे