通过可替换函数,我的意思是像C ++中的new
和delete
运算符,如果提供了用户提供的定义,它们将被替换。
对于除运算符new
和delete
(在C / C ++中)之外的其他情况,是否有一种合理的可移植方式在库中实现此目的?或者是否需要为每个实现单独解决这个问题?
对于一个具体的例子,我们假设该库包含:
int the_answer(void) {
return 42;
}
然后使用它的程序想要覆盖它:
int the_answer(void) {
return 43;
}
int main() {
printf("The answer is %d\n", the_answer());
}
它应该导致它打印"答案是43" (但如果评论出the_answer
的最后一个定义,它会写出#34;答案是42")。
实际用例是通过覆盖默认行为的数据来自定义库的行为。
答案 0 :(得分:3)
在C ++中,您可以使用模板的优先级低于不需要隐式转换/构造参数的实现的事实。
// library function
template <class = void>
int the_answer() { return 42; }
// optional override
int the_answer() { return 43; }
请注意,定义顺序并不重要,模板总是丢失。
答案 1 :(得分:0)
当然,对于除运营商之外的任何事情。请注意,C没有运算符重载,因此您的问题被错误标记。
对于函数/变量/常量,您可以定义一个宏来执行预期的操作。当重载(或者更换),#undef
宏并定义一个新宏。适用于C或C ++,虽然非常危险。
在C中,不能选择重载或替换功能。要么必须使用预处理器,如上所述,要么实际编辑生成的二进制文件以使用您的函数。
在C ++中,您可以创建一个使用虚函数的多态类,覆盖以前的定义。这将是覆盖库本身操作的最简单的解决方案。
在任何一种语言中,如果不重新编译,就很难改变变量的类型或常量的值。
答案 2 :(得分:-2)
假设您的图书馆以这种方式定义doCoffee()
函数:
void doCoffee_impl() { /* ... */ }
void (doCoffee*)(void) = doCoffee_impl;
然后,您的图书馆用户可以通过重新影响全局变量来替换doCoffee的行为。
但是,嘿!你正在编写C ++。为什么不使用虚拟operator()
?
struct Brewer
{
virtual operator()() { /* ... */ }
} brewer;
brewer *doCoffee = &brewer;
您的用户可能会超载:
struct UserBrewer : public Brewer
{
virtual operator()() { /* ... */ }
} userBrewer;
doCoffee = &userBrewer;
让读者:在源头中声明变量static或者定义extern,并在提供的编译单元中定义变量。