首页 文章

CRTP的静态多态性:使用基类调用派生方法

提问于
浏览
4

C中 virtual 的主要好处之一是能够使用基类(指针或引用)来调用派生方法 .

我正在读using CRTP to implement static polymorphism,但我可以使用这种技术't understand how to achieve what I'上面提到,因为当需要模板时,我无法将函数声明为类型 Base .

在我看来,文章中描述的内容可以通过简单地使用函数重载来实现,所以我确信这个技术必须有更多 .

(PS:对this question的答案的评论中提到了这个确切的问题,但遗憾的是没有人回复它:"What vtables truly provide is using the base class (pointer or reference) to call derived methods. You should show how it is done with CRTP here.")

这是我的最小代码,它给出了错误“在'&'令牌无效打印(基础和对象)之前缺少模板参数” .

#include <cstring>
#include <iostream>

template <typename Derived>
struct Base
{
    std::string ToStringInterface() { return static_cast<Derived*>(this)->ToString(); }

    std::string ToString()  {   return "This is Base.";     }
};

struct Derived : Base<Derived>
{
    std::string ToString()  {   return "This is Derived.";  }
};

void Print(Base& Object)
{
    std::cout << Object->ToStringInterface() << std::endl;
}

int main()
{
    Derived MyDerived;

    // This works, but could have been achieved with a function overload.
    std::cout << MyDerived.ToStringInterface() << std::endl;

    // This does not work.
    Print(MyDerived);
}

3 回答

  • 4

    对不起,但CRTP确实没有这种方式 . 这个想法通常是以一种非常特定于C的方式将一些代码注入依赖关系层次结构 . 在您的示例中,您可以使用例如需要 ToStringInterface() 函数并使用CRTP将其绑定到现有类层次结构的 ToString() 的接口:

    class IStringable
    {
        virtual string ToStringInterface() = 0;
    };
    class Unchangeable
    {
        virtual string ToString();
    };
    template<class Derived>
    class UnchangeableToIStringableMixin
    {
        virtual string ToStringInterface()
        {
            return static_cast<Derived*>(this)->ToString();
        }
    };
    class StringableUnchangeable:
        public Unchangeable, UnchangeableToIStringableMixin<StringableUnchangeable>
    {
    };
    

    但是,如果实际上可以更改 Unchangeable ,那么您就不会忘记CRTP可能不适合您正在做的事情 .

  • 3

    那么,你需要声明打印模板功能:

    template<class T>
    void Print(Base<T>& Object)
    {
        std::cout << Object.ToStringInterface() << std::endl;
    }
    
  • 4

    感谢收到的评论和答案,我发布了我的实施,以防它对其他人有用 .

    #include <cstring>
    #include <iostream>
    
    template <typename Derived>
    class Base
    {
    public:
        std::string ToStringInterface()
        {
            return static_cast<Derived*>(this)->ToString();
        }
    };
    
    template<>
    class Base<void> : public Base<Base<void> >
    {
    public:
        std::string ToString()
        {
            return "This is Base (default implementation).";
        }
    };
    
    class Derived : public Base<Derived>
    {
    public:
        std::string ToString()
        { 
            return "This is Derived.";
        }
    };
    
    template <typename T>
    void Print(Base<T>& Object)
    {
        std::cout << Object.ToStringInterface() << std::endl;
    }
    
    int main()
    {   
        int Decision;
        std::cout << "Do you want to create an object of type Base (input 0) or Derived (input 1)? ";
        std::cin >> Decision;
        if (Decision == 0)
        {
            Base<void> MyBase;
            Print(MyBase);
        }
        else
        {
            Derived MyDerived;
            Print(MyDerived);
        }
    }
    

相关问题