C++ 多态性c+的方法链+;
是否可以编写返回派生类型的fluent Channing方法?考虑以下两个类:C++ 多态性c+的方法链+;,c++,polymorphism,fluent,C++,Polymorphism,Fluent,是否可以编写返回派生类型的fluent Channing方法?考虑以下两个类: class Base { protected: std::string mFoo; public: Base& withFoo(std::string foo) { mFoo = foo; return *this; } }; class Derived : public Base { protected: std::string mBar;
class Base {
protected:
std::string mFoo;
public:
Base& withFoo(std::string foo) {
mFoo = foo;
return *this;
}
};
class Derived : public Base {
protected:
std::string mBar;
public:
Derived& withBar(std::string bar) {
mBar = bar;
return *this;
}
void doOutput() {
std::cout << "Foo is " <<
mFoo << ". Bar is " <<
mBar << "." << std::endl;
}
};
这当然会失败,因为withFoo
返回一个Base
。由于我所有的with
方法都只是设置成员变量,因此我可以先用s指定派生的。问题是我的生成器方法(doOutput
,在上面的示例中)需要是一个单独的语句
Derived d;
d.withBar("this is a bar")
.withFoo("this is my foo");
d.doOutput();
我的问题是withFoo
是否有某种方法返回未知的派生类型,以便Base
可以无缝地用于多个派生类(毕竟,*这是一个派生的,尽管Base
(正确地说)不知道这一事实)
作为一个更具体的例子,我正在编写几个类来访问REST服务器。我有一个RestConnection
类和一个GettableRest
类和一个doGet
类。我怀疑这是不可能的,可能会尝试将一堆虚拟方法塞进RestConnection
中,但我不喜欢在有多个with param
重载时这样做,其中一些没有意义包含在GET参数列表中
提前谢谢 看一看
如果Base
是一个抽象类型(仅在其子类中实例化),则将其作为使用类型名称的模板。您的Derived
将扩展模板-例如Derived:public Base
。如果Base是一个具体的类型,那么您需要引入一个新的抽象类,它将是Base
和派生的
的基类型
通过这种方式,withFoo
可以被模板化以返回实际类型。我认为您可以在这里使用,类似于下面的内容,其中派生类告诉基类它是什么类型:
class Base
{
// Abstract/virtual interface here.
};
template <class Derived>
class Base_T : public Base
{
private:
std::string mFoo;
public:
Derived& withFoo(std::string foo) {
mFoo = foo;
return *static_cast<Derived*>(this);
}
};
class Derived : public Base_T<Derived> {
private:
std::string mBar;
public:
Derived& withBar(std::string bar) {
mBar = bar;
return *this;
}
void doOutput() {
std::cout << "Foo is " <<
mFoo << ". Bar is " <<
mBar << "." << std::endl;
}
};
类基
{
//这里是抽象/虚拟接口。
};
模板
类基\u T:公共基
{
私人:
std::字符串mFoo;
公众:
派生&withFoo(标准::字符串foo){
mFoo=foo;
返回*static_cast(此);
}
};
派生类:公共基\u T{
私人:
std::字符串mBar;
公众:
派生和withBar(标准::字符串栏){
毫巴=巴;
归还*这个;
}
void doOutput(){
std::cout您可以选择CRTP(如Mark B所示),或者在变量名上使用运行时调度,例如
Derived d;
d.with("Foo", "foo").with("Bar", "bar").doOutput();
这不会特别有性能,但它非常灵活,非常适合使用任意字段的协议。因为您的类型不是多态的(没有虚拟函数),所以Base不知道派生的
通过静态多态性,您可以从本质上达到目标:
template<class Derived>
class Base {
protected:
std::string mFoo;
public:
Derived& withFoo(std::string foo) {
mFoo = foo;
return static_cast<Derived&>(*this);
}
};
class Derived : public Base<Derived> {
protected:
......
}
这仍然采用了经典的OOP范例,但增加了运行时开销(vtables),并且具有基于特性(虚拟函数的协变返回类型)的缺点并非所有编译器都支持。您可以给Base一个模板参数,并在它从Base继承时将其自身作为参数传递给派生类。现在Base可以返回对此模板参数的引用。您可能对Decorator模式感兴趣。您是否还需要从Base
到各种派生类的运行时多态性一般来说,受保护的属性(不是方法)是一种强烈的设计味道,因为它们允许容易违反不变量。实际上,您有类型省略(可能是c回调某些类型函数void*对象)马克,你建议在这种情况下使用static\u cast
还是声明一个虚拟基析构函数并使用dynamic\u cast(*this)
?举个例子。@WhozCraig我绝对推荐static\u cast
,因为继承保证类型在所有情况下都是正确的。dynamic\u cast
会增加开销,没有额外的好处。对不起,我问这个问题只是因为每当我看到对cast操作的取消引用时,我都会感到恐慌。另外,(不相关)在你的例子中,代码< Base< /Cord>不是模板,我想你是指“代码>类派生:Pub BaseTo/<代码>,但是在这里太早了,我知道WTF我正在走动= p(+CRTP方法的1),这正是我需要的!我已经走下了模板路径,但我还没有处理过C++。(主要是爪哇语)。我自己唯一无法弄清楚的部分是withFoo的返回类型,但这给了我预期的结果。静态强制转换有什么警告吗?@WhozCraig你说得对,我错过了Base\t
继承-在答案中得到了修复。实际上这还不错。其他答案更具体地针对我的问题,但我看不出来他在各种情况下都很有用,特别是在设计阶段,事情可能会不断变化。我想+1这一点,但没有这样的名声:/
template<class Derived>
class Base {
protected:
std::string mFoo;
public:
Derived& withFoo(std::string foo) {
mFoo = foo;
return static_cast<Derived&>(*this);
}
};
class Derived : public Base<Derived> {
protected:
......
}
class Base
{
...
virtual Base& withFoo(...);
...
virtual ~Base() {} //just to make all the hierarchy destructible through base
};
class Derived: public Base
{
...
virtual Derived& withFoo(type arg)
{ return static_cast<Derived&>(Base::withFoo(arg)); }
...
};