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

发布于 2024-10-06 04:34:27 字数 1778 浏览 2 评论 0原文

我想构建一个 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 用户不会出现链接时或运行时错误?

提前致谢!

I'd like to build an API that provides a class interface to functionality (header file) and hide the implementation for all the standard good reasons. I plan on using an object factory to return object pointers of derived "newed" objects which conform to the interface.

My core API class varies based on std::vectors of built-in numeric types(char, uchar, short, ushort, int, uint, float and double). So a template seems like a natural fit. I'll make an interface class template available to the users of my API and derive from it in the implementation class template which will be hidden.

Since my user visible class template is an interface class I'd like to declare all the methods pure virtual but I understand there may problems with doing this given required template instantiations/exports in dlls, shared objects, etc. So I'll just define them virtual and give them empty method bodies in the base interface class. Somewhere along the line I need to create a template static factory method (or template function) that will create the objects of the derived classes and return pointers to them to the caller.

The issue is I cannot put the implementation of the static object factory method in the interface header file either as it has to create objects of the derived classes which are to be hidden. So I'd like to put these static object factories in the implementation header or a source file.

Here is a conceptual implementation header

#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

Here is a conceptual derived implementation class

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

};

Note: In reality I'll be using TR1::shared_ptr instead of raw pointers.

My questions are:

1) Where do I define the static "factoryMethod( )" method (implementation.h or implementation.cpp)?

2) What does this method implementation look like?

3) Are there any other issues I need to be aware of so I or my API users don't get link time or run-time errors?

thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

帅气尐潴 2024-10-13 04:34:27

您将遇到这样的问题:

1) 模板不能由像这样的 DLL 公开,因为它们是在编译时“填充”的。也就是说,如果您有 DerivedClass,编译器实际上会在您定义对象的“T”处填写“int”。尝试通过 DLL 公开它时,客户端代码(将尝试与您的对象链接的应用程序)可能会尝试创建 DerivedClass 对象,并且您将收到链接器错误,因为它不不存在。

2) 虽然 C++ 标准在技术上允许将模板类拆分为实现和头文件,但没有编译器支持该功能(因为尝试实现是一件非常痛苦的事情)。这包括 Microsoft 的 C++ 编译器。有几种方法可以解决这个问题:将类内联写入头文件中(这是大多数 STL 实现所做的),或者在头文件底部使用 #include 实现文件(这本质上是同样的事情,但并不是真正的标准做法)。

You will run into problems with this:

1) Templates cannot be exposed by DLLs like this as they are "filled in" at compile time. That is, if you have DerivedClass<int>, the compiler actually fills in "int" everywhere you have "T" to define the object. Trying to expose it via a DLL, the client code (the application that will try to link with your object) could try to create a DerivedClass<int> object and you will get a linker error because it doesn't exist.

2) While the C++ standard technically allows for template classes to be split into implementation and header files, no compiler has supported that feature (as it is a royal pain to attempt to implement). This includes Microsoft's C++ compiler. There are a couple ways around this: write the class inline in the header file (which is what most STL implementations do), or #include the implementation file at the bottom of the header file (which essentially does the same thing, but is not really standard practice).

时间你老了 2024-10-13 04:34:27

我让它在 Visual studio 2008 下工作。

下面是详细信息:

interface.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

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

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

I got it to work under Visual studio 2008.

Below are the details:

interface.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

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

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

This may be non-standard but it is very useful.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文