替代c ++静态虚方法 [英] Alternative to c++ static virtual methods

查看:162
本文介绍了替代c ++静态虚方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C ++中不可能声明一个静态虚函数,既不能将非静态函数强制转换为C风格函数指针。

In C++ is not possible to declare a static virtual function, neither cast a non-static function to a C style function pointer.

现在,使用函数指针的大量的。

Now, I have a plain ol' C SDK that uses function pointers heavily.

我必须用几个函数指针填充一个结构。我计划使用一个抽象类和一堆静态纯虚方法,并重新定义它们在派生类中,并用它们填充结构。直到那时,我意识到静态虚拟是不允许在C + +。

I have to fill a structure with several function pointers. I was planning to use an abstract class with a bunch of static pure virtual methods, and redefine them in derived classes and fill the structure with them. It wasn't until then that I realized that static virtual are not allowed in C++.

此外,这个C SDKs函数签名没有userData参数。

Also this C SDKs function signature doesn't have a userData param.

有没有好的替代品?最好的我想到的是定义一些纯虚拟方法GetFuncA(),GetFuncB(),...和一些静态成员FuncA()/ FuncB()在每个派生类,将由GetFuncX()返回。然后,抽象类中的函数将调用这些函数来获取指针并填充结构。

Is there any good alternative? The best I can think of is defining some pure virtual methods GetFuncA(), GetFuncB(),... and some static members FuncA()/FuncB() in each derived class, which would be returned by the GetFuncX(). Then a function in the abstract class would call those functions to get the pointers and fill the structure.

编辑
回答John Dibling,这将是巨大的能够做到这一点:

Edit Answering to John Dibling, it would be great to be able to do this:

class Base
{
    FillPointers() { myStruct.funA = myFunA; myStruct.funB = myFunB; ...}
private:
    CStruct myStruct;
    static virtual myFunA(...) = 0;
    static virtual myFunB(...) = 0;
};

class Derived1 : public Base
{
    Derived1() {  FillPointers();  }
    static virtual myFunA(...) {...};
    static virtual myFunB(...) {...};
};

class Derived2 : public Base
{
    Derived2() {  FillPointers();  }
    static virtual myFunA(...) {...};
    static virtual myFunB(...) {...};
};

int main()
{
    Derived1 d1;
    Derived2 d2;
    // Now I have two objects with different functionality
}


推荐答案

您可以使 Base 是一个类模板,它从其模板参数取其函数指针:

You can make Base be a class template that takes its function pointers from its template argument:

extern "C" {
struct CStruct
{
  void (*funA)(int, char const*);
  int (*funB)(void);
};
}

template <typename T>
class Base
{
public:
  CStruct myStruct;
  void FillPointers() {
    myStruct.funA = &T::myFunA;
    myStruct.funB = &T::myFunB;
  }
  Base() {
    FillPointers();
  }
};

然后,定义派生类,从 Base 使用每个派生类作为模板参数:

Then, define your derived classes to descend from an instantiation of Base using each derived class as the template argument:

class Derived1: public Base<Derived1>
{
public:
  static void myFunA(int, char const*) { }
  static int myFunB() { return 0; }
};

class Derived2: public Base<Derived2>
{
public:
  static void myFunA(int, char const*) { }
  static int myFunB() { return 1; }
};

int main() {
  Derived1 d1;
  d1.myStruct.funA(0, 0);
  d1.myStruct.funB();
  Derived2 d2;
  d2.myStruct.funA(0, 0);
  d2.myStruct.funB();
}

这种方法被称为奇怪的重复模板模式。如果你忽略在派生类中实现其中一个函数,或者更改函数签名,你会得到一个编译错误,这正是你所期望的,如果你忽略了实现一个纯虚拟

That technique is known as the curiously recurring template pattern. If you neglect to implement one of the functions in a derived class, or if you change the function signature, you'll get a compilation error, which is exactly what you'd expect to get if you neglected to implement one of the pure virtual functions from your original plan.

然而,这种技术的结果是 Derived1 Derived2 没有公共基类。 Base 的两个实例对于类型系统而言不以任何方式相关。如果你需要他们相关,那么你可以引入另一个类作为模板的基础,然后把共同的东西放在那里:

The consequence of this technique, however, is that Derived1 and Derived2 do not have a common base class. The two instantiations of Base<> are not related in any way, as far as the type system is concerned. If you need them to be related, then you can introduce another class to serve as the base for the template, and then put the common things there:

class RealBase
{
public:
  CStruct myStruct;
};

template <typename T>
class Base: public RealBase
{
  // ...
};

int main()
  RealBase* b;
  Derived1 d1;
  b = &d1;
  b->myStruct.funA(0, 0);
  b->myStruct.funB();
  Derived2 d2;
  b = &d2;
  b->myStruct.funA(0, 0);
  b->myStruct.funB();
}

注意:静态成员函数不一定兼容用普通函数指针。根据我的经验,如果编译器接受上面所示的赋值语句,那么至少可以确定它们与该编译器兼容。 此代码不可移植,但如果它适用于您需要支持的所有平台,那么您可能认为它足够便携。

Beware: Static member functions are not necessarily compatible with ordinary function pointers. In my experience, if the compiler accepts the assignment statements shown above, then you can at least be confident that they're compatible for that compiler. This code isn't portable, but if it works on all the platforms you need to support, then you might consider it "portable enough."

这篇关于替代c ++静态虚方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆