Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.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
C++ 多态性c+的方法链+;_C++_Polymorphism_Fluent - Fatal编程技术网

C++ 多态性c+的方法链+;

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;

是否可以编写返回派生类型的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;
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)); }
   ...
};