我希望有两个实现A.h A.c和B.h B.c 他们声明了相同的方法,唯一的区别是.c文件中的实现。
但是现在我的重复符号出现了链接错误。
答案 0 :(得分:2)
更改名称。
没有"命名空间"在C.他们被添加到C ++。在C中,全局范围内的所有内容都必须具有唯一的名称。
所以给你的东西添加前缀
A_Function1
A_Function2
B_Function1
B_Function2
等
如果你只需要1个实现(比如一个用于Mac而另一个用于Windows),那么当然只链接一个或使用#if
关闭一个
// a.h
#if USE_A
...
#endif // USA_A
// a.c
#if USE_A
...
#endif // USE_A
对于B.然后在编译时可以使用
cc -DUSE_A=1
否则,如果你需要在运行时切换实现(比如OpenGL vs DirectX后端),这通常是用函数指针完成的。
你制作了另一个带有函数指针的文件。然后使用实现A或B中的任一函数填充那些指向函数的指针。所有其他文件仅引用函数指针。
// a.h
int A_SomeFunc(int arg1);
// a.c
#include "a.h"
int A_SomeFunc(int arg1) {
...
}
// b.h
int B_SomeFunc(int arg1);
// b.c
#include "b.h"
int B_SomeFunc(int arg1) {
...
}
// virtual.h
extern int (*SomeFunc)(int arg1);
void Init(int implementation) // 0 = A, 1 = B
// virtual.c
#include "a.h"
#include "b.h"
int (*SomeFunc)(int arg1);
void Init(int implementation) {
switch (implementation) {
case 0: // use A
SomeFunc = A_SomeFunc;
break;
case 1: // use B;
SomeFunc = B_SomeFunc;
break;
}
}
现在,在程序开始的某个地方,您需要致电Init
。然后其他文件可以包含virtual.h
,并将使用您在Init
中选择的任何实现。
要将其提升到新的水平,请将SomeFunc
放入结构中。
struct SomeAPI {
int (*SomeFunc)(int arg1);
};
现在更改Init以填写SomeAPI
void Init(struct SomeAPI* someAPI, int implementation) {
switch (implementation) {
case 0: // use A
someAPI->SomeFunc = A_SomeFunc;
break;
case 1: // use B;
someAPI->SomeFunc = B_SomeFunc;
break;
}
}
现在,您已经有效地制作了C ++类的虚函数。其他模块会做类似
的事情struct SomeAPI api;
Init(&api, 1); // choose B
int result = api.SomeFunc(someIntArgument);
或者
struct SomeAPI* pAPI = malloc(sizeof(SomeAPI));
Init(pAPI, 1); // choose B
int result = api->SomeFunc(someIntArgument);