C ++中virtual
的主要好处之一是能够使用基类(指针或引用)来调用派生方法。
我正在阅读using CRTP to implement static polymorphism,但我无法理解如何使用此技术实现我上面提到的内容,因为我无法将函数声明为采用类型Base
这需要一个模板。
在我看来,文章中描述的内容可以通过简单地使用函数重载来实现,所以我确信这项技术必须有更多。
(PS:对this question的答案的评论中提到了这个确切的问题,但不幸的是没有人回复它:“vtables真正提供的是使用基类(指针或引用)来调用派生方法。你应该在这里展示如何使用CRTP。“)
这是我的最小代码,它给出错误“在'&'标记之前缺少模板参数 void Print(Base& Object)“。
#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);
}
答案 0 :(得分:4)
嗯,您需要声明打印模板功能:
template<class T>
void Print(Base<T>& Object)
{
std::cout << Object.ToStringInterface() << std::endl;
}
答案 1 :(得分: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);
}
}
答案 2 :(得分:3)
很抱歉,但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对于你正在做的事情不是正确的工具的可能性。