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