【发布时间】:2016-07-16 05:20:31
【问题描述】:
我正在通过其 C++ SDK 为应用程序编写插件。机制相当简单。插件通过预定义的接口提供其功能。这是通过让服务器类从每个接口的一个实现类继承来完成的,该实现类包含纯虚拟函数或具有默认实现的非纯函数。
这是非常实用的,因为 SDK 客户端只需覆盖插件所需的那些方法和/或为(罕见的)那些没有默认值的方法提供实现。
困扰我的是,在编译时一切都是已知的。与运行时多态性相关的虚函数表和机器在这里只是为了提供默认实现。
我试图在保持便利的同时消除这种开销。
作为一个(非常人为的)示例,假设我有几个服务器提供一个接口(名为 Blah),该接口仅由一个方法组成,没有默认实现。
// SDK header
struct OldImpl_Blah {
virtual ~OldImpl_Blah() =default;
virtual int mult(int) =0;
};
// plugin source
class OldServer3 : public OldImpl_Blah {
public:
int mult(int i) override { return 3 * i; }
};
class OldServer5 : public OldImpl_Blah {
public:
int mult(int i) override { return 5 * i; }
};
对于纯虚函数,直接 CRTP 就可以了。
// SDK header
template <typename T>
struct NewImpl_Blah {
int mult(int i) { return static_cast<T*>(this)->mult(i); }
};
// plugin source
class NewServer3 : public NewImpl_Blah<NewServer3> {
public:
int mult(int i) { return 3 * i; }
};
class NewServer5 : public NewImpl_Blah<NewServer5> {
public:
int mult(int i) { return 5 * i; }
};
问题在于非纯虚函数,即当方法有默认实现时。
// SDK header
struct OldImpl_Blah {
virtual ~OldImpl_Blah() =default;
virtual int mult(int i) { return i; } // default
};
// plugin source
class OldServer3 : public OldImpl_Blah {
public:
int mult(int i) override { return 3 * i; }
};
class OldServer5 : public OldImpl_Blah {
public:
int mult(int i) override { return 5 * i; }
};
我尝试将 CRTP 与一些表达式 SFINAE 技巧结合起来,但失败了。
我想我需要的是某种代码调度,其中基类要么提供默认实现,要么将其参数转发给派生类中的实现(如果存在)。
问题似乎是调度应该依赖于基类中编译器尚不可用的信息。
一个简单的解决方案是删除代码中的virtual 和override 关键字。但是编译器不会检查函数签名是否匹配。
这种情况有一些众所周知的模式吗?我要问的有可能吗?
(请使用小字,因为我在模板方面的专业知识有点轻。谢谢。)
【问题讨论】:
-
你可以在什么版本的C++下编译?
-
“编译器不会检查函数签名是否匹配”。您能否通过提供代码示例来说明这可能会产生哪些不良影响?
-
@AndyG:我正在使用 VS 2015 更新 1。那会是 C++14 吗?
-
@n.m.:我不确定我是否理解你的问题。例如,如果用户在名称中打错字,它将创建一个新函数。
-
CRTP 没有等效的“override”关键字(表示希望隐藏具有相同签名的基类的非虚拟成员函数)。你问的是这个吗?
标签: c++ inheritance virtual crtp