如何确保派生类实现特定方法,保持标准布局?
Posted
技术标签:
【中文标题】如何确保派生类实现特定方法,保持标准布局?【英文标题】:How to ensure that derivative classes implement particular methods, retaining standard layout? 【发布时间】:2015-09-01 17:11:44 【问题描述】:我正在创建一个基类,它有一些在派生类中使用的方法。这个基类有点像抽象类,除了(protected
)方法之外,它还定义了必须在派生类中实现的接口(即public
)方法。但它并不打算用作多态基础,而是它的派生类将用作其他一些函数/仿函数的模板参数,这些函数/函子将调用接口方法。
鉴于上述情况,我可以使用通常的方法来定义抽象类,例如使用纯虚函数,但是这样做有一个问题:生成的派生类需要具有标准布局。因此不允许使用虚函数。但是仍然会有很多衍生品,直到稍后才会使用,我想让编译器检查所有需要的方法是否使用正确的签名实现(例如int Derived::f(double)
而不是int Derived::f(float)
不允许)。
考虑到标准布局的要求,这样做的好方法是什么?
【问题讨论】:
也许奇怪重复的模板模式有帮助。所以你的基类调用派生类方法,但是解析是在编译时完成的。 听起来像是概念。见boost.org/doc/libs/1_58_0/libs/concept_check/concept_check.htm @TobySpeight 你为什么不使用“答案”框来写你的答案但使用评论? (@DieterLücking) @Alex - 因为这是推测而不是完整的答案。我没有时间亲自尝试。 @TobySpeight 基类如何检查该方法不仅兼容,而且完全符合要求? (请参阅问题中的示例:int Derived::f(double)
而不是 int Derived::f(float)
是不允许的)。
【参考方案1】:
这是 CRTP 模式的实现,在接口调度例程中带有 static_assert
:
#include <iostream>
#include <type_traits>
template<class Derived>
class enable_down_cast
typedef enable_down_cast Base;
public:
// casting "down" the inheritance hierarchy
Derived const* self() const return static_cast<Derived const*>(this);
Derived* self() return static_cast<Derived* >(this);
protected:
// disable deletion of Derived* through Base*
// enable deletion of Base* through Derived*
~enable_down_cast() = default;
;
template<class FX>
class FooInterface
:
public enable_down_cast< FX >
using enable_down_cast< FX >::self; // dependent name now in scope
public:
int foo(double d)
static_assert(std::is_same<decltype(self()->do_foo(d)), int>::value, "");
return self()->do_foo(d);
protected:
// disable deletion of Derived* through Base*
// enable deletion of Base* through Derived*
~FooInterface() = default;
;
请注意,上面的static_assert
仅在接口的返回类型和实现不匹配时才会触发。但是您可以使用任何您希望的类型特征来装饰此代码,并且这里有 plenty of Q&As 在 SO 上编写类型特征以检查接口和实现之间的精确函数签名匹配。
class GoodFooImpl
:
public FooInterface< GoodFooImpl >
private:
friend class FooInterface< GoodFooImpl > ;
int do_foo(double) std::cout << "GoodFooImpl\n"; return 0;
;
class BadFooImpl
:
public FooInterface< BadFooImpl >
private:
friend class FooInterface< BadFooImpl >;
char do_foo(double) std::cout << "BadFooImpl\n"; return 0;
;
int main()
GoodFooImpl f1;
BadFooImpl f2;
static_assert(std::is_standard_layout<GoodFooImpl>::value, "");
static_assert(std::is_standard_layout<BadFooImpl>::value, "");
f1.foo(0.0);
f2.foo(0.0); // ERROR, static_assert fails, char != int
Live Example on Coliru.注意派生类确实是标准布局。
【讨论】:
以上是关于如何确保派生类实现特定方法,保持标准布局?的主要内容,如果未能解决你的问题,请参考以下文章