如何在C ++中切换2个函数集?

时间:2011-02-06 22:47:36

标签: c++ c function performance

有没有办法,我可以有效地在两个相似的功能集(C / C ++)之间切换? 为了更好地解释我的意思,假设我有两组全局函数,如:

void a_someCoolFunction();
void a_anotherCoolFunction(int withParameters);
…

void b_someCoolFunction();
void b_anotherCoolFunction(int withParameters);
…

我希望能够在运行时“切换”我的程序中使用哪一个。但是:我不想在每个函数中有一个条件,例如:

void inline someCoolFunction(){
    if(someState = A_STATE){
        a_someCoolFunction();
    }else{
        b_someCoolFunction();
    }
}

因为,我希望在我的主循环中调用每个函数 - 所以如果我可以做这样的事情(在我的mainloop的开头或someState被更改时)会更好:

if(someState = A_STATE){
    useFunctionsOfType = a;
}else{
    useFunctionsOfType = b;
}

然后简单地调用

useFunctionsOfType _someCoolFunction();

我希望它可以理解我的意思...我的背景:我正在编写一个应用程序,应该能够正确处理OpenGL ES 1.1和OpenGL ES 2.0 - 但我不想写每次渲染方法2次(如:{ {1}}和renderOpenGL1()我宁愿只写renderOpenGL2())。我已经有类似的方法,如:render() ...但需要一种方法在这两种方式之间切换。 有没有办法以高效的方式实现这一目标?

7 个答案:

答案 0 :(得分:8)

有几个选项,包括(但不限于):

  • 使用函数指针。
  • 将它们包装在类中,并使用多态。
  • 有两个单独的循环副本。

但请个人资料以确保实际上出现问题,之前您对代码进行了大量更改。

答案 1 :(得分:4)

由于这个问题似乎对C ++解决方案感兴趣并且没有人详细说明多态解决方案(太明显了?),所以这就是。

使用您需要的API定义抽象基类,然后为每个受支持的实现实现派生类:

class OpenGLAbstract
{
   public:
       virtual ~OpenGLAbstract() {}
       virtual void loadIdentity() = 0;
       virtual void someFunction() = 0;
};

class OpenGLEs11 : public OpenGLAbstract
{
   public:
       virtual void loadIdentity()  
       {
           // Call 1.1 API

       }
       virtual void someFunction() 
       {
           // Call 1.1 API
       }
};


class OpenGLEs20 : public OpenGLAbstract
{
   public:
       virtual void loadIdentity()  
       {
           // Call 2.0 API
       }
       virtual void someFunction() 
       {
           // Call 2.0 API
       }
};

int main()
{
    // Select the API to use:
    bool want11 = true;
    OpenGLAbstract* gl = 0;
    if (want11)
        gl = new OpenGLEs11;
    else
        gl = new OpenGLEs20;

    // In the main loop.
    gl->loadIdentity();

    delete gl;
}

请注意,这正是C ++的用途,所以如果可以在这里使用C ++,这是最简单的方法。

现在,您可能遇到的一个更微妙的问题是,如果您的2.0版本要求进程在运行时使用2.0平台实现加载动态链接库。在这种情况下,仅仅支持API开关是不够的(无论解决方案如何)。而是将每个OpenGL具体类放在它自己的链接库中,并在每个类中提供一个工厂函数来创建该类:

OpenGlAbstract* create();

然后在运行时加载所需的库并调用create()方法来访问API。

答案 2 :(得分:2)

您可以使用函数指针。如果你谷歌它,你可以阅读很多关于它们,但简单地说,函数指针存储指向函数的内存地址的指针。

函数指针的使用方式与函数相同,但可以赋予不同函数的地址,使其成为某种“动态”函数。举个例子:

typedef int (*func_t)(int);


int divide(int x) {
    return x / 2;
}

int multiply(int x) {
    return x * 2;
}

int main() {
    func_t f = ÷
    f(2); //returns 1
    f = &multiply;
    f(2); //returns 4
}

答案 3 :(得分:2)

在C中(因为你似乎想要C和C ++)这是通过指向函数的指针完成的。

// Globals. Default to the a_ functions
void(*theCoolFunction)()           = a_someCoolFunction;
void(*theOtherCoolFunction)(int)   = a_anotherCoolFunction;

// In the code ...
{
  ...
  // use the other functions 
  theCoolFunction = b_someCoolFunction;
  theOtherCoolFunction = b_anotherCoolFunction;
  ...
}

您可能希望在组中切换这些函数,因此最好设置一个指向函数的指针数组并传递该数组。如果您决定这样做,您可能还想定义一些宏来简化阅读:

   void (*functions_a[2])();
   void (*functions_b[2])();

   void (**functions)() = functions_a;

   ....
   #define theCoolFunction()       functions[0]()
   #define theOtherCoolFunction(x) functions[1](x) 
   ....

    // switch grooup:
   functions = functions_b;

但在这种情况下,您将失去对参数类型的静态检查(当然,您必须初始化数组)。

我想在C ++中你将使用相同的父类和不同的方法实现两个不同的对象(但我不是C ++程序员!)

答案 4 :(得分:2)

像boost :: function(std :: function)这样的东西符合要求。使用您的示例:

#include <iostream>
#include <boost/function.hpp> //requires boost installation
#include <functional> //c++0x header


void a_coolFunction() {

    std::cout << "Calling a_coolFunction()" << std::endl;
}

void a_coolFunction(int param) {

     std::cout << "Calling a_coolFunction(" << param << ")" << std::endl;
}

void b_coolFunction() {

    std::cout << "Calling b_coolFunction()" << std::endl;
}

void b_coolFunction(int param) {

    std::cout << "Calling b_coolFunction(" << param << ")" << std::endl;
}
float mul_ints(int x, int y) {return ((float)x)*y;}


int main() {

    std::function<void()> f1;  //included in c++0x 
    boost::function<void(int)> f2; //boost, works with current c++
    boost::function<float(int,int)> f3;

    //casts are necessary to resolve overloaded functions
    //otherwise you don't need them
   f1 = static_cast<void(*)()>(a_coolFunction);
   f2 = static_cast<void(*)(int)>(a_coolFunction);

   f1();
   f2(5);

   //switching
   f1 = static_cast<void(*)()>(b_coolFunction);
   f2 = static_cast<void(*)(int)>(b_coolFunction);

   f1();
   f2(7);

   //example from boost::function documentation.  No cast required.
   f3 = mul_ints;
   std::cout << f3(5,3) << std::endl;

}

使用g ++ - 4.4.4编译,输出:

Calling a_coolFunction()
Calling a_coolFunction(5)
Calling b_coolFunction()
Calling b_coolFunction(7)
15

最大的限制是f1,f2等的类型不能改变,因此你赋给它们的任何函数必须具有相同的签名(即在f2的情况下为void(int))。

答案 5 :(得分:1)

简单的方法可能是存储指向函数的指针,并根据需求进行更改。

但更好的方法是使用类似于abstract factory设计模式的东西。可以在Loki library中找到很好的通用实现。

答案 6 :(得分:1)

在C中,您通常会使用包含struct函数指针的方法执行此操作:

struct functiontable {
    void (*someCoolFunction)(void);
    void (*anotherCoolFunction)(int);
};

const struct functiontable table_a = { &a_someCoolFunction, &a_anotherCoolFunction };
const struct functiontable table_b = { &b_someCoolFunction, &b_anotherCoolFunction };

const struct functiontable *ftable = NULL;

要切换活动功能表,您可以使用:

ftable = &table_a;

要调用这些函数,您可以使用:

ftable->someCoolFunction();