C++使用接口类、模板和对象工厂构建API

C++使用接口类、模板和对象工厂构建API,c++,visual-studio,templates,factory,factory-pattern,C++,Visual Studio,Templates,Factory,Factory Pattern,我想构建一个API,为功能头文件提供一个类接口,并出于所有标准的原因隐藏实现。我计划使用对象工厂返回符合接口的派生新对象的对象指针 我的核心API类根据内置数字类型的std::vectors而有所不同—Schar、uchar、short、ushort、int、uint、float和double。因此,模板似乎是一种自然的匹配。我将为API的用户提供一个接口类模板,并在将隐藏的实现类模板中从中派生 由于我的用户可见类模板是一个接口类,我想将所有方法都声明为纯虚拟的,但我知道在DLL、共享对象等中给

我想构建一个API,为功能头文件提供一个类接口,并出于所有标准的原因隐藏实现。我计划使用对象工厂返回符合接口的派生新对象的对象指针

我的核心API类根据内置数字类型的std::vectors而有所不同—Schar、uchar、short、ushort、int、uint、float和double。因此,模板似乎是一种自然的匹配。我将为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用户不会出现链接时间或运行时错误


提前谢谢

您将遇到以下问题:

1类DLL不能公开模板,因为它们是在编译时填充的。也就是说,如果您有DerivedClass,编译器实际上会在需要定义对象的任何地方填充int。如果试图通过DLL公开它,则尝试与您的对象链接的应用程序的客户端代码可能会尝试创建DerivedClass对象,您将收到链接器错误,因为它不存在


< 2 >虽然C++技术上允许模板类被分割为实现和头文件,但是编译器没有支持该特性,因为尝试实现它是一种巨大的痛苦。这包括微软的C++编译器。有两种方法可以解决这个问题:在头文件中内联编写类,这是大多数STL实现所做的,或者在头文件的底部包含实现文件,这基本上做了相同的事情,但不是真正的标准做法。

我让它在Visual studio 2008下工作

详情如下:

接口.h

#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
导出的.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

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

这可能是非标准的,但它非常有用。

一个编译器,CuMuC++,支持模板类的分割。该选项几乎肯定会从标准中删除,Comeau支持这样做。我在VisualStudio2008下使用了它