c++ - 用 CRTP 替换非纯虚函数

标签 c++ inheritance virtual crtp

我正在通过其 C++ SDK 为应用程序编写插件。该机制相当简单。插件通过预定义的接口(interface)提供其功能。这是通过让服务器类从每个接口(interface)的一个实现类继承来完成的,该实现类包含纯虚函数或具有默认实现的非纯函数。
这非常实用,因为 SDK 客户端只需覆盖插件所需的那些方法和/或为(罕见的)没有默认值的方法提供实现。

一直困扰我的是,一切都在编译时已知。与运行时多态相关的虚函数表和机制在这里只是为了提供默认实现。
我试图在保持便利的同时消除这种开销。

作为一个(非常人为的)示例,假设我有几个服务器提供一个接口(interface)(名为 Blah),该接口(interface)仅包含一个没有默认实现的方法。

// 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 技巧结合起来,但失败了。
我想我需要的是某种代码调度,其中基类要么提供默认实现,要么将其参数转发给派生类中的实现(如果存在)。
问题似乎是分派(dispatch)应该依赖于基类中编译器尚不可用的信息。

一个简单的解决方案是删除代码中的 virtualoverride 关键字。但是编译器不会检查函数签名是否匹配。
这种情况有一些众所周知的模式吗?我问的是可能的吗?

(请使用小字,因为我对模板的专业知识有点浅。谢谢。)

最佳答案

与往常一样,另一个间接级别是解决方案。在这种特殊情况下,这是众所周知的公共(public)非虚函数调用私有(private)或 protected 虚函数的技术。它有自己的用途,与这里讨论的内容无关,所以无论如何都要检查一下。通常它是这样工作的:

struct OldImpl_Blah {
piblic:
    virtual ~OldImpl_Blah() = default;
    int mult(int i) { return mult_impl(i); }
protected:
    virtual int mult_impl(int i) { return i; }
};

// plugin source
class OldServer3 : public OldImpl_Blah {
protected:
    int mult_impl(int i) override { return 3 * i; }
};

对于 CRTP,它完全一样:

template <class T>
struct OldImpl_Blah {
piblic:
    virtual ~OldImpl_Blah() = default;
    int mult(int i) { return static_cast<T*>(this)->mult_impl(i); }
protected:
    virtual int mult_impl(int i) { return i; }
};

// plugin source
class OldServer3 : public OldImpl_Blah<OldServer3> {
protected:
    int mult_impl(int i) override { return 3 * i; }
};

免责声明:CRTP 据说通过要求函数是虚拟 来消除虚拟调用开销。我不知道当函数保持 virtual 时 CRTP 是否有任何性能优势。

关于c++ - 用 CRTP 替换非纯虚函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36270985/

相关文章:

c++ - condition_variable,引用和线程:谁拥有锁?

c++ - 使用DCMTK读取3D Dicom图像并将其转换为OpenCV Mat

.htaccess - 具有通配符映射的虚拟子域 .htaccess

java - 我如何使用通用参数覆盖 EJB 3 session bean 方法 - 如果可能的话?

java - 从 Java 中的基类访问子类字段

C++:访问虚拟方法

c++ - operator<< 内部的虚方法调用

c++ - 带有返回值的 if 语句代码样式

c++ - constant 和 reinterpret cast 是否在编译时发生?

inheritance - 使用嵌入式接口(interface)字段在 Go 中正确实现继承