首页 > 解决方案 > 指向函数的对象指针

问题描述

我读了一段标题代码,发现如下:

ObjPtr.h:

#include <dlfcn.h>

#define OBJPTR(X)        void* X##Ptr ;         \
                            void* (*X##ObjPtr)() ;

void * CreateObj(void * handler, char* LibName, char* FunctionName);

事务.c

//...
OBJPTR(DB);
//...
DBObjPtr = CreateObj(DBPtr, "DBTransaction", "Function1");
if ((unsigned long)(DBObjPtr)(csPara1, csPara2) != PD_FOUND)
{
    //...

首先,我不明白头文件中的定义行是什么意思。(为什么定义行中有 X##?这是什么意思?)

其次,在c文件中创建对象而不是直接调用函数。我认为这种设计的目的是为了在对象之间进行隔离,以便于维护和解决方案的构建/交付;或来自不同开发人员的代码加密,如果我是正确的。但还有什么?或者这种设计模式是什么样的?

标签: c++pointersdesign-patterns

解决方案


##是预处理器的 (!) 连接。在给定的情况下,使用宏会创建两个变量:

OBJPTR(DB);

将解决:

void* DBPtr;
void* (*DBObjPtr)();

实际上,我们在这里找到的不是有效的 C++(这就是您标记问题的内容):

  1. void* (*DBObjPtr)()声明一个接受参数的函数指针,但稍后会使用其中两个参数调用它。
  2. 声明的函数返回指向 void 的指针,但它在没有任何强制转换的情况下分配给函数指针。

此代码仅在 C 中有效(void* (*DBObjPtr)()声明一个未定义参数列表的函数指针;无参数函数需要显式void作为参数:void* (*x)(void)!),并且 C 允许从指向 void 的指针隐式转换为其他指针类型。

意图可能是在 C 中提供某种多态性:

DBObjPtr = CreateObj
(
    // probably used as some kind of handle; as not being passed
    // as pointer to pointer, the function cannot re-assign, but
    // only use it; so I assume that is has been initialized at
    // some point before this function call...
    DBPtr,
    // some kind of identifier from where to load a function from for
    // later use; as the parameter is called "library", it might load
    // the address of a function within a SO (*nix) or DLL (windows)
    "DBTransaction",
    // the name of the function to load
    "Function1"
);

在 C++ 中,您可能会以不同的方式处理它:

class Loader;

Loader* db = createLoader(); // initialization lacking in your sample code;
                             // alternatively (and probably better!) via constructor
void* (*fptr)(int, int) = db->createObj("L", "F");

这还行不通,我们还需要应用一些更改。首先,我们需要改变函数的返回类型,它必须返回一个接受任意参数的函数指针。您可以让它返回任意参数(通过省略号)或只有一个空参数列表 - 没关系,无论如何您都必须转换结果(除非使用第二个变体并且加载的函数确实不接受任何参数。 ..)。但是从 C++11 开始,有一种更优雅的方式来做这些事情,该函数可以实现为可变参数模板函数:

class Loader
{
public:
    template <typename ... TT>
    auto createObj(char const*, char const*) -> void*(*)(TT ...);
};

然后演员表将隐藏在函数中,您可以简单地将其用作:

auto f = loader->createObj<int, int>("L", "F");
// ^ yeah, let's profit from C++11 again...

只是如果您好奇:C++ 11 之前的方式:

class Loader
{
public:
    void* (*createObj())(...);
    // function returning function pointer - ugly syntax, I know
    // (a typedef for the function pointer makes reading a little easier...)
};

void*(*f)(int, int) = reinterpret_cast<void*(*)(int, int)>(create());

对原始宏的最后一点说明:我个人不会使用它,即使在 C 语言中也不会!对于懒惰的人来说,这可能看起来不错,但实际上只是混淆了变量的声明,并且另外产生了较少类型安全的函数指针。所以我会自己声明变量:

void* db /*= ...*/ ;
void* (*f)(int, int) = createObj(db, "L", "F");
//         ^    ^    already with correct parameter list

推荐阅读