现在几乎所有内容都已经讲完了,我想添加一个答案,允许一个人在多个继承级别上使用CRTP:
我想在我的班级中使用更改器(设置器)以返回this
以允许类似jQuery的a.name("something").address("somethingelse");
我有一个父类(Entity
)和几个子类(Client, Agent etc.
)。大多数事物的转换器都继承自Entity
类(例如名称或地址),但是它们返回Entity
对象,因此我无法在其上调用客户端转换器。
换句话说:
// name mutator
Entity& Entity::name( const string& name ) {
// [...] checks
_name = name;
return *this;
}
// budgetRange mutator
Client& Client::budgetRange( const long int& range ) {
// [...] checks
_budgetRange = range;
return *this;
}
然后我叫它:
Client a; a.name("UserName123").budgetRange(50);
编译器(从逻辑上说,该Entity对象没有budgetRange成员(因为名称返回一个Entity,而不是Client)。
我现在的问题是:我怎样才能实现这样的目标?我曾考虑过重载子类中的所有Entity函数,但这不是很好,并且违背了继承的概念:)
预先感谢您的想法:D
您应使用CRTP。
template<class Derived>
class Entity
{
Derived* This() { return static_cast<Derived*>(this); }
public:
Derived& name(const string& name)
{
...
return *This();
}
};
class Client : public Entity<Client>
{
public:
Client& budgetRange(const long& range)
{
...
return *this;
}
};
如果要使用虚函数,还可以添加抽象基类,如下所示:
class AbstractEntity
{
public:
virtual void foo() = 0;
virtual ~AbstractEntity();
};
template<class Derived>
class Entity : AbstractEntity
{...};
“好奇递归模板”模式可以在这里提供帮助;使基类成为模板,该模板由派生类参数化:
template <typename Derived> struct Entity { Derived & name(std::string const & name) { // stuff return static_cast<Derived&>(*this); } }; struct Client : Entity<Client> { Client & budget(long range) { // stuff return *this; } }; Client().name("Mike").budget(50); // should compile
仅当您所有类型都直接继承自
Entity
时,此方法才有效。如果您需要类型为多态的(即,所有类型都共享一个公共基类),则需要添加另一个非模板基类,并让Entity
继承。
现在几乎所有内容都已经讲完了,我想添加一个答案,允许一个人在多个继承级别上使用CRTP:
上述CRTP实现在想要从Client
继承时会中断,因为Derived
将引用Client
。如果您希望能够使用CRTP模式在多个继承级别上携带命名参数惯用语,则需要像这样对类进行编码]
template<class Derived> class Entity_T { protected: Derived* This() { return static_cast<Derived*>(this); } public: Derived& name(const string& name) { ... return *This(); } }; template<class Derived> class Client_T : public Entity_T<Derived> { Derived& budgetRange(const long& range) { ... return *This(); } };
为用户提供
Client_T
添加的无模板版本>class Client : public Client_T<Client> {};
这是否值得扩展代码库完全取决于您。注意,我还没有编译上面的代码。
现在几乎所有内容都已经讲完了,我想添加一个答案,允许一个人在多个继承级别上使用CRTP: