有没有办法,我可以有效地在两个相似的功能集(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()
...但需要一种方法在这两种方式之间切换。
有没有办法以高效的方式实现这一目标?
答案 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();