24

から派生したFoo<T>との2 つのクラスがあります。それぞれが methodをオーバーライドします。ここで、 はorの特定のインスタンス化を一意に識別する型のインスタンスです(それが であるふりをします)。問題は、がインスタンスを返せるようにする必要があり、同様に をインスタンス化できる必要があることです。どちらもテンプレートであるため、 と の間に循環依存関係が発生します。これを解決するにはどうすればよいですか?Bar<T>Basevirtual Base* convert(ID) constIDFooBarenumFoo::convert()BarBar::convert()FooFoo.hBar.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.

    ...

}

エラーは、当然、「不完全な型の無効な使用」です。

4

4 に答える 4

21

あなたがする必要があるのは、実装からクラス宣言を分離することです。だから何か

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

このようにして、関数が定義されるときに完全なクラス定義が得られます。

于 2010-07-28T14:37:25.850 に答える
18

(更新) テンプレート以外のクラスと同じように処理できるはずです。Bar.h を次のように記述します。(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
于 2010-07-28T14:26:47.383 に答える
13

いずれかのヘッダーでテンプレート クラスの前方宣言を使用する必要があります。

template <class T>
class X;

完全に良いテンプレートクラスの前方宣言です。

于 2010-07-28T14:28:16.093 に答える
10

ジェームズ・カランの答えは天の恵みです。一般的に、Jamesのアイデアは、インクルードされたヘッダーファイルからのmembers('宣言)が必要になるまで、必要なヘッダーファイルのインクルードを制限することです。例として:

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>&)
}
于 2011-07-17T22:36:50.677 に答える