Does static polymorphism make sense for implementing an interface?

and Merry Christmas to all!

I learn about static polymorphism, and I read Andrei Alexandrescu an excellent book on political design. In my code, I came across the following: I have an interface Interfacethat indicates that a method should be present Foo. This interface will be implemented by the class Impl. I have the following two options:

1) Dynamic polymorphism

class Interface {
public:
    virtual void Foo() = 0;
}

class Impl : public Interface {
public:
    void Foo() {};
}

2) Static polymorphism

class Impl {
{
public:
    void Foo() {};
}

template <class I>
class Interface : public I
{
public:
    void Foo() { I::Foo(); } //not actually needed
}

? - ? , - , , , , .

: ; .

+2
2

.

.

( ). , , 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
}

, , :

#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")

:

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)

. , final class Child final : public Interface.

, :

void bar(Child& child) { child.Foo(); } // may call Child::Foo not virtually.

( bar ):

void bar(Interface& child) { child.Foo(); } // have to virtual call Foo.

, :

void Interface::Bar() { /* some code */ Foo(); }

, Foo.

, :

template<class Derived>
void Interface<Derived>::Bar() { /* some code */ static_cast<Derived*>(this)->Foo(); }
+3

, , .

. ( ).

. . . , . , , , .

+1

Source: https://habr.com/ru/post/1680744/


All Articles