2010-12-06 18 views
0

機能(ヘッダーファイル)に対するクラスインターフェイスを提供するAPIを構築し、すべての標準的な理由で実装を非表示にしたいと考えています。私は、オブジェクトファクトリを使用して、インタフェースに準拠した派生した「新しい」オブジェクトのオブジェクトポインタを返すことを計画しています。C++インターフェイスクラス、テンプレート、およびオブジェクトファクトリを使用したAPIの構築

コアAPIのクラスは、組み込み数値型(char、uchar、short、ushort、int、uint、float、double)のstd :: vectorsに基づいて異なります。テンプレートは自然にフィットするようです。私は、私のAPIのユーザーが利用できるインターフェイスクラステンプレートを作成し、それを隠す実装クラステンプレートで派生させます。

私のユーザーが見ることができるクラステンプレートはインターフェイスクラスなので、純粋な仮想メソッドを宣言したいと思っていますが、ここで必要なテンプレートインスタンス化/エクスポートをdllや共有オブジェクトなどで行うと問題が発生することがあります。それらを仮想的に定義して、基本インターフェースクラスに空のメソッド本体を与えます。どこかに沿って、派生クラスのオブジェクトを作成し、呼び出し側にポインタを返すテンプレート静的ファクトリメソッド(またはテンプレート関数)を作成する必要があります。

問題は、非表示にする派生クラスのオブジェクトを作成する必要があるため、静的オブジェクトファクトリメソッドの実装をインターフェイスヘッダーファイルに配置できません。だから私はこれらの静的オブジェクトファクトリを実装ヘッダーまたはソースファイルに入れたいと思います。ここ

ここ

#ifndef INTERFACE_H 
#define INTERFACE_H 

#ifdef DLL_EXPORTS 
#define DLL_API __declspec(dllexport) 
#else 
#define DLL_API __declspec(dllimport) 
#endif 

// This interface class is exported from the dll. 

template < typename T > 
class DLL_API InterfaceClass { 
public: 
static InterfaceClass* factoryMethod(); 
virtual ~InterfaceClass () { } 

virtual void someMethod(T aParam){ }; 

protected: 
InterfaceClass () { } 

private: 
InterfaceClass (const InterfaceClass &); 
InterfaceClass& operator=(const InterfaceClass &); 
}; 

#endif 

は概念的派生実装クラス

#ifndef IMPLEMENTATION_H 
#define IMPLEMENTATION_H 

#include <vector> 
#include "interface.h" 

template < typename T > 
class DerivedClass : public InterfaceClass<T> { 
public: 
DerivedClass(const T& aDataVector) : InterfaceClass<T>() { /*...*/ } 

virtual ~DerivedClass() { /*...*/ } 

virtual void someMethod(T aParam) { /*...*/ } 
private: 
std::vector<T> _dataVector; 

}である概念的な実装ヘッダです。

注:実際には、生ポインタの代わりにTR1 :: shared_ptrを使用します。

私の質問は以下のとおりです。

1)どこで私は、静的な "factoryMethod()" メソッド(implementation.hまたはimplementation.cpp)を定義するのですか?

2)このメソッドの実装はどのように見えますか?

3)私または私のAPIユーザーがリンク時または実行時エラーを受け取らないように注意する必要がある他の問題はありますか?

ありがとうございます!

+0

Visual Studio 2008の下で動作させました – intensifi

答えて

0

あなたはこの問題に実行されます:彼らはコンパイル時に「記入」されているよう

1)テンプレートは、このようなのDLLによって公開されることはできません。つまり、DerivedClass<int>がある場合、コンパイラは実際にオブジェクトを定義するために "T"を持つすべての場所で "int"を埋め込みます。 DLLを介して公開しようとすると、クライアントコード(オブジェクトとリンクしようとするアプリケーション)がDerivedClass<int>オブジェクトを作成しようとする可能性があり、存在しないためリンカーエラーが発生します。

2)C++標準では、技術的にテンプレートクラスを実装ファイルとヘッダーファイルに分割することができますが、コンパイラはその機能をサポートしていません(実装しようとすると苦労するため)。これにはMicrosoftのC++コンパイラが含まれます。これにはいくつかの方法があります:ヘッダーファイル(ほとんどのSTL実装が行うもの)にインラインでクラスを書くか、または#includeヘッダーファイルの最後にインプリメンテーションファイルを作成します(基本的に同じことですが、標準的な練習)。

+1

1つのコンパイラ、Comeau C++がテンプレートクラスの分割をサポートしました。オプションはほぼ確実に標準から削除され、Comeauはこれをサポートします。 –

0

私は以下2008

が詳細ですそれは、Visual Studioの下で動作するようになった:

#ifndef INTERFACE_H 
#define INTERFACE_H 

#if defined(WIN32) || defined (WIN64) 

#ifdef DLL_EXPORTS 
#define DECLSPECIFIER __declspec(dllexport) 
#define EXPIMP_TEMPLATE 
#else // DLL_EXPORTS 
#define DECLSPECIFIER __declspec(dllimport) 
#define EXPIMP_TEMPLATE extern 
#endif // DLL_EXPORTS 

#else // defined(WIN32) || defined (WIN64) 
#define DECLSPECIFIER 
#define EXPIMP_TEMPLATE 
#endif // defined(WIN32) || defined (WIN64) 

// This class is exported from the dll. 

template < typename T > 
class DECLSPECIFIER InterfaceClass { 
public: 
static InterfaceClass* factoryMethod(); 
virtual ~InterfaceClass() { } 

virtual void someMethod() { } 

protected: 
InterfaceClass() { } 

private: 
InterfaceClass(const InterfaceClass&); 
InterfaceClass& operator=(const InterfaceClass&); 
}; 

#if defined(WIN32) || defined (WIN64) 
#pragma warning(push) 
#pragma warning(disable: 4231) // "nonstandard extension used : 'extern' 
           // ok per [link text][1] 
#endif 

#include <vector> 

EXPIMP_TEMPLATE template class DECLSPECIFIER InterfaceClass < std::vector<char> >; 
EXPIMP_TEMPLATE template class DECLSPECIFIER InterfaceClass < std::vector< unsigned char > >; 
EXPIMP_TEMPLATE template class DECLSPECIFIER InterfaceClass < std::vector<short> >; 
EXPIMP_TEMPLATE template class DECLSPECIFIER InterfaceClass < std::vector< unsigned short > >; 
EXPIMP_TEMPLATE template class DECLSPECIFIER InterfaceClass < std::vector<int> >; 
EXPIMP_TEMPLATE template class DECLSPECIFIER InterfaceClass < std::vector< unsigned int > >; 
EXPIMP_TEMPLATE template class DECLSPECIFIER InterfaceClass < std::vector<float> >; 
EXPIMP_TEMPLATE template class DECLSPECIFIER InterfaceClass < std::vector<double> >; 

#if defined(WIN32) || defined (WIN64) 
#pragma warning(pop) 
#endif 

#endif 

derived.h

#ifndef DERIVED_H 
#define DERIVED_H 

#include <iostream> 

#include "interface.h" 

template < typename T > 
class DerivedClass : public InterfaceClass<T> { 
public: 
DerivedClass() { 
    std::cout << "constructing derived class" << std::endl; 

} 

virtual ~DerivedClass() { 
    std::cout << "destructing derived class" << std::endl; 
} 

virtual void someMethod() { 
    std::cout << "hello" << std::endl; 
} 
private: 
T _data; 
}; 

#endif 

interface.cpp interface.h

#include "interface.h" 
#include "derived.h" 

template < typename T > 
DECLSPECIFIER 
InterfaceClass<T>* InterfaceClass<T>::factoryMethod() { 
    return new DerivedClass<T>(); 
} 

client.cpp

#include <exception> 

#include "interface.h" 

typedef InterfaceClass < std::vector<int> > IntVectorType; 

int main(int argc, char* argv[]) 
{ 
IntVectorType* ptrTest = NULL; 
try { 
    ptrTest = IntVectorType::factoryMethod(); 
} 
catch (std::bad_alloc&) { 
    return 1; 
} 

ptrTest->someMethod(); 

delete ptrTest; 

return 0; 
} 

これは、非標準のかもしれないが、それは非常に便利です。

関連する問題