2011-01-24 33 views
0

私が書こうとしているC++ライブラリに問題があります。通常のセットアップ、1つのcppファイル、1つのヘッダーファイルです。ヘッダーファイルには、使用する部分のみが公開されます(ヘッダーファイルには必要ない抽象基本クラスがあります)。これまでのところ、私はただ一つのファイルで作業しています(これは何の違いもないはずです、何も気にしないプリプロセッサによって行われます)。C++クラスの宣言と名前空間

「ヘッダーファイル」は、ヘッダー実装ファイルの前後に2箇所に広がっています。

#include <stdio.h> 

// lib.h 
namespace foo { 
    template <class T> class A; 
} 

// lib.cpp 
namespace foo { 
    template <class T> class A { 
     private: 
     T i; 
     public: 
     A(T i) { 
      this->i = i; 
     } 

     T returnT() { 
      return i; 
     } 
    }; 
}; 

// lib.h 
namespace foo { 
    template <class T> T A<T>::returnT(); 
} 

// foo.cpp 
void main() { 
    foo::A<int> a = foo::A<int>(42); 
    printf("a = %d",a.returnT()); 
} 

だから、当然、私はちょうど

namespace foo { 
    template <class T> class A; 
    template <class T> T A<T>::returnT(); 
} 

を含むように私のヘッダファイルを希望しかし、私のコンパイラは、この(それはreturnTfoo::A<T>のメンバーではないと文句を言い。理由は私が好きではありません。クラス宣言そのものをヘッダーに入れたくないということは、私が理解しているように、プライベートなものとそれに類するものをすべて含んでいることです。私は隠したいものです。

多分それは私です。しかし、次のヘッダーファイルは少なくとも「悪い」と思われます"インターフェイス仕様"と呼ばれています。Aの内部構造の一部を公開していますが、libのユーザーはそれについて知る必要はありません。

// lib.h 
namespace foo { 
    template <class T> class A { 
     private: 
     int i; 
     public: 
     A(T); 
     T returnT(); 
    }; 
} 

// lib.cpp 
namespace foo { 
    template <class T> A<T>::A(T i) { 
     this->i = i; 
    } 
    template <class T> T A<T>::returnT() { 
     return i; 
    } 
}; 

これは受け入れられる方法ですか?可能であれば、より抽象的なヘッダーファイルが必要です。

+0

をヘッダファイルのコードコードの全体の最初のブロックですか? "lib.h"とラベルされた2つのブロックがあるので混乱していますが、そこに 'main'関数があります。 –

+0

' template'という単語を書くときに、実装の詳細を公開しています。これはどのように動作するか、期間です。メインヘッダーに '#include 'という"実装ヘッダーファイル "を作ることができますが、ソースを出荷する必要があります。 –

+0

@ James McNellis:最初のコード部分(灰色のブロック)は、すべてを1つのファイルに保存するために使用した単なるテストファイルです。これは、これが 'lib.h'、' lib.cpp'と 'main.cpp'の3つのファイルに分割され、最後は' user'テストだけで 'lib'を呼び出すという考え方です。問題はちょうど私が望むようなものを得るためには、私はヘッダーを実装コードの上の1つの部分とその下の1つの部分に分割する必要があるということです。それは理にかなっていますか? – Svend

答えて

2

あなたはここで扱っているの.cppファイルには二つの問題があります:コンパイラのニーズ(あなたのメイン()で行うように)あなたがスタック上にそのクラスのインスタンスを配置する場合

I. は、クラスのサイズを知る(十分なメモリを割り当てる)。そのためにはメンバーを知る必要があり、それによって完全な宣言が必要です。

クラスのレイアウトを非表示にする唯一の方法は、インターフェイスとファクトリメソッド/ファンクションを構築し、そのインスタンスをファクトリのヒープに配置することです。 (テンプレートなし;理由を知り下記参照)の例として

:あなたは

namespace foo { 
    class IA { 
    public: 
     virtual ~IA(); 
     virtual int returnT() = 0; 

     static IA *Create(); 
    }; 
} 

。あなたは、その後行うCPP:ところで

namespace foo { 
    class A : public IA { 
    private: 
     int i; 
    public: 
     A() : 
     i(0) { 
     } 
     virtual ~A() { 
     } 
     virtual int returnT() { 
     return i; 
     } 
    }; 
    IA::~IA() { 
    } 

    IA *IA::Create() { 
    return new A(); 
    } 
} 

:スマートポインタを使用すると...

IIを示唆したことになります。 テンプレートを使用しているため、メソッド定義はヘッダーファイルで表示するか、特定の種類のセットに対して明示的にインスタンス化する必要があります。

lib.h:

namespace foo { 
    template <typename T> class IA { 
    public: 
     virtual ~IA() { 
     } 
     virtual T returnT() = 0; 

     static IA *Create(); 
    }; 
} 

lib_impl.h:そうあなたが

namespace foo { 
    template <typename T> class A : public IA<T> { 
    private: 
     T i; 
    public: 
     A() : 
     i(T()) { 
     } 
     virtual ~A() { 
     } 
     virtual T returnT() { 
     return i; 
     } 
    }; 

    template <typename T> IA<T> *IA<T>::Create() { 
    return new A<T>(); 
    } 
} 

は、だから、lib.hとlib_impl.hにコードを分割することができますlib_impl.hをインクルードする必要があります。 は、明示的なインスタンスがlib.cppを追加し、ちょうどそのファイルがlib_impl.hを含めることができるようにしましょう使用するには:

lib.cpp:

#include <lib_impl.h> 
namespace foo { 
    template class IA<int>; 
    template class A<int>; 
    template class IA<float>; 
    template class A<float>; 
    template class IA<char>; 
    template class A<char>; 
    // ... 
} 
+0

この素晴らしい答えに追加するには、lib.hの最後にlib_impl.hを#includeすることもできます。このようにして、ユーザーの視点から、lib.hへの簡単な見方は、lib_impl.hの詳細を見る必要もなく、またlib_implがいつ呼び出されるかを特定する特別な作業をする必要もなく、本質(インターフェース) .hはインクルードされるべきかどうか。 –

+0

このアプローチ(FAQでも概説)は、私が最後にやったことです。スマートポインターは私がどこにいるのかかなり分かりません;) – Svend

+0

私は質問があります。私が理解しているように、lib.cppは、どのテンプレートを生成するかについて、コンパイラに対するヒントとして使われています。 FAQにはこのアプローチ(項目35.13)も記載されていますが、この構文は具体的には何ですか?どこでStroustrupsの本を見て何かを学べますか? – Svend

5

テンプレートの定義を宣言から分離することはできません。彼らは一緒にヘッダーファイルに入る必要があります。

"なぜですか?"私は"Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?"を読むことをお勧めします。


質問が誤っている可能性があります。また、あなたの質問であるかもしれないものに対処するために、これは有効ではありません:それは同じ理由で有効ではありません

namespace foo { 
    template <class T> class A;  
    template <class T> T A<T>::returnT(); 
} 

これが有効でないこと:

namespace foo { 
    class A; 
    int A::returnT(); 
} 

メンバ関数は、定義内で宣言されなければなりませんクラスの

+0

よくある質問は、問題が何であるかを辛抱強く明確にしています。ありがとう! – Svend

+0

@スヴェーデン:はい。私は助けられてうれしいです。 –

関連する問題