Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
CRTP静态多态性:使用基类调用派生方法 < > C++中的代码>虚拟的主要好处之一是能够使用基类(指针或引用)调用派生方法。_C++_Templates_Polymorphism_Crtp - Fatal编程技术网

CRTP静态多态性:使用基类调用派生方法 < > C++中的代码>虚拟的主要好处之一是能够使用基类(指针或引用)调用派生方法。

CRTP静态多态性:使用基类调用派生方法 < > C++中的代码>虚拟的主要好处之一是能够使用基类(指针或引用)调用派生方法。,c++,templates,polymorphism,crtp,C++,Templates,Polymorphism,Crtp,我正在阅读,但我不明白如何使用此技术实现上面提到的内容,因为当需要模板时,我不能将函数声明为使用typeBase 在我看来,这篇文章中描述的内容可以通过简单地使用函数重载来实现,因此我确信这项技术还需要更多的内容 (PS:在对答案的评论中提到了这个确切的问题,但不幸的是没有人回答它:“vtables真正提供的是使用基类(指针或引用)调用派生方法。您应该在这里展示如何使用CRTP来完成它。”) 这是我的最小代码,它给出了错误“在“&”标记之前缺少模板参数” 无效打印(基本和对象)” #包括 #包括

我正在阅读,但我不明白如何使用此技术实现上面提到的内容,因为当需要模板时,我不能将函数声明为使用type
Base

在我看来,这篇文章中描述的内容可以通过简单地使用函数重载来实现,因此我确信这项技术还需要更多的内容

(PS:在对答案的评论中提到了这个确切的问题,但不幸的是没有人回答它:“vtables真正提供的是使用基类(指针或引用)调用派生方法。您应该在这里展示如何使用CRTP来完成它。”)

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

#包括
#包括
模板
结构基
{
std::string ToStringInterface(){return static_cast(this)->ToString();}
std::string ToString(){return“This is Base.”;}
};
派生结构:基
{
std::string ToString(){return“这是派生的。”;}
};
无效打印(基础和对象)
{

std::cout-ToStringInterface()那么,您需要声明一个模板函数:

template<class T>
void Print(Base<T>& Object)
{
    std::cout << Object.ToStringInterface() << std::endl;
}
模板
无效打印(基础和对象)
{

Std::CUT< P>对不起,但是CRTP确实不这样做。这个想法通常是以C++的特定方式向依赖层次结构中注入一些代码。在您的示例中,可以有一个需要<代码> toStrutIdFrice()的接口。
函数,并使用CRTP将其绑定到现有类层次结构的
ToString()

类可设置为IStringable
{
虚拟字符串toString接口()=0;
};
类不变
{
虚拟字符串ToString();
};
模板
类unchangabletoStringableMixin
{
虚拟字符串toString接口()
{
返回static_cast(this)->ToString();
}
};
类StringableUnchange:
公共不可更改,不可更改为StringableMixin
{
};

但是,如果<代码>不可更改的<代码>实际上可以被改变,你不会做这样的事情。不要忘记考虑CRTP不是你正在做的正确的工具的可能性。

< P>由于收到的评论和答案,我发布了我的实现,以防它对其他人有用。
#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);
    }
}
#包括
#包括
模板
阶级基础
{
公众:
std::字符串到字符串接口()
{
返回static_cast(this)->ToString();
}
};
模板
类基:公共基
{
公众:
std::string ToString()
{
返回“这是基础(默认实现)”;
}
};
派生类:公共基
{
公众:
std::string ToString()
{ 
return“这是派生的。”;
}
};
模板
无效打印(基础和对象)
{

std::cout“因为当需要模板时,我不能将函数声明为使用类型Base。”函数
Print
必须是静态多态性的函数模板,是的--类似于
模板void Print(Base&Object);
。静态多态性在编译时解决,因此
Print
必须准确知道在编译时调用哪个函数。这正是我所需要的。一个小的后续问题:在这种情况下,我不能为Base使用默认方法,也不能实例化Base类型的对象,对吗?(这可以通过动态多态性实现)。您可以创建一个类型为
Base
的实例,该实例实际上不是
任何类型的
,但调用
ToStringInterface()
将调用未定义的行为。请保护该ctor,并/或在
ToStringInterface()中检查正确的类型
。请注意,使用
动态\u cast
进行检查并不总是可能的,因为CRTP不一定涉及任何虚拟功能,但这些都是此类cast所必需的。谢谢。我这样做更多的是为了在模板中进行练习,满足我的好奇心,而不是为了其他任何事情。实际上,我不明白为什么我会使用这些coComplexity而不仅仅是使用
virtual
。最终我找到了一个我喜欢的解决方案,用
void
专门化
Base
类(见下文)@Ulrich IMHO您不需要在成员函数上使用virtual,即使这是CRTP的主要优点,在编译时执行virtual,您也将拥有更快的exec,因为它不需要在运行时浏览虚拟表。
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>
{
};
#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);
    }
}