Dan*_*tor 5 c++ polymorphism templates policy-based-design static-polymorphism
和大家圣诞快乐!
我正在学习静态多态性,并且正在阅读Andrei Alexandrescu关于基于策略的设计的出色著作。我在代码中遇到了以下内容:我有一个接口Interface,指定Foo必须存在该方法。该接口将由class实现Impl。我有以下两种选择:
1)动态多态
class Interface {
public:
virtual void Foo() = 0;
}
class Impl : public Interface {
public:
void Foo() {};
}
Run Code Online (Sandbox Code Playgroud)
2)静态多态
class Impl {
{
public:
void Foo() {};
}
template <class I>
class Interface : public I
{
public:
void Foo() { I::Foo(); } //not actually needed
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下使用静态多态性有意义吗?与第一种方法相比,第二种方法有什么好处吗?该接口仅指定了某些方法的存在,并且其机制对于不同的实现是相同的-因此与书中描述的情况不太一样,因此我觉得我可能只是在使事情变得过于复杂。
更新:我在运行时不需要多态行为;在编译时已知正确的实现。
动态多态确实迫使孩子尊重接口。
静态多态不会强制孩子尊重接口(直到你真正调用函数),所以,如果你不提供有用的方法,你可以直接使用Impl.
class InvalidImpl {}; // Doesn't respect interface.
void bar()
{
InvalidImpl invalid;
// this compiles, as not "expected" since InvalidImpl doesn't respect Interface.
CRTP_Interface<InvalidImpl> crtp_invalid;
#if 0 // Any lines of following compile as expected.
invalid.Foo();
crtp_invalid.Foo();
#endif
}
Run Code Online (Sandbox Code Playgroud)
您有第三种使用特征来检查类是否验证接口的方法:
#include <cstdint>
#include <type_traits>
// Helper macro to create traits class to know if class has a member method
#define HAS_MEM_FUNC(name, Prototype, func) \
template<typename U> \
struct name { \
typedef std::uint8_t yes; \
typedef std::uint16_t no; \
template <typename T, T> struct type_check; \
template <typename T = U> \
static yes &chk(type_check<Prototype, &T::func> *); \
template <typename > static no &chk(...); \
static constexpr bool value = sizeof(chk<U>(0)) == sizeof(yes); \
}
// Create traits has_Foo.
HAS_MEM_FUNC(has_Foo, void (T::*)(), Foo);
// Aggregate all requirements for Interface
template <typename T>
struct check_Interface :
std::integral_constant<bool, has_Foo<T>::value /* && has_otherMethod<T>::value */>
{};
// Helper macros to assert if class does respect interface or not.
#define CHECK_INTERFACE(T) static_assert(check_Interface<T>::value, #T " doesn't respect the interface")
#define CHECK_NOT_INTERFACE(T) static_assert(!check_Interface<T>::value, #T " does respect the interface")
Run Code Online (Sandbox Code Playgroud)
使用 C++20 概念,可以用不同的方式编写 trait:
// Aggregate all requirements for Interface
template <typename T>
concept InterfaceConcept = requires(T t)
{
t.foo();
// ...
};
#define CHECK_INTERFACE(T) static_assert(InterfaceConcept<T>, #T " doesn't respect the interface")
Run Code Online (Sandbox Code Playgroud)
让我们测试一下:
class Interface {
public:
virtual void Foo() = 0;
};
class Child_Impl final : public Interface {
public:
void Foo() override {};
};
#if 0 // Following doesn't compile as expected.
class Child_InvalidImpl final : public Interface {};
#endif
template <class I>
class CRTP_Interface : public I
{
public:
void Foo() { I::Foo(); } // not actually needed
};
class Impl { public: void Foo(); }; // Do respect interface.
class InvalidImpl {}; // Doesn't respect interface.
CHECK_INTERFACE(Interface);
CHECK_INTERFACE(Child_Impl);
CHECK_INTERFACE(Impl);
CHECK_INTERFACE(CRTP_Interface<Impl>);
CHECK_NOT_INTERFACE(InvalidImpl);
CHECK_INTERFACE(CRTP_Interface<InvalidImpl>); // CRTP_Interface<T> _HAS_ Foo (which cannot be invoked)
Run Code Online (Sandbox Code Playgroud)
使用动态多态,您可以为虚拟呼叫付费。您可以通过添加finalas来减少一些虚拟调用class Child final : public Interface。
所以编译器可能会优化如下代码:
void bar(Child& child) { child.Foo(); } // may call Child::Foo not virtually.
Run Code Online (Sandbox Code Playgroud)
但它不能做任何魔术(假设bar没有内联):
void bar(Interface& child) { child.Foo(); } // have to virtual call Foo.
Run Code Online (Sandbox Code Playgroud)
现在,假设在您的界面中您有:
void Interface::Bar() { /* some code */ Foo(); }
Run Code Online (Sandbox Code Playgroud)
我们处于第二种情况,我们必须虚拟呼叫Foo。
静态多态通过以下方式解决了这个问题:
template<class Derived>
void Interface<Derived>::Bar() { /* some code */ static_cast<Derived*>(this)->Foo(); }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1402 次 |
| 最近记录: |