具有多态性 C++ 的方法链接
method chaining with polymorphism c++
是否可以编写返回派生类型的流畅方法? 请考虑以下两个类:
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;
}
};
然后我想构建我的对象并像这样使用它:
Derived d;
d.withFoo("foo").withBar("bar").doOutput();
这当然会失败,因为withFoo
返回一个Base
。 由于我所有的with
方法都只是设置成员变量,所以我可以先指定派生with
。 问题是我的构建器方法(doOutput
在上面的示例中(需要是一个单独的语句。
Derived d;
d.withBar("this is a bar")
.withFoo("this is my foo");
d.doOutput();
我的问题是withFoo
是否有某种方法返回未知的派生类型,以便Base
可以与多个派生类无缝使用(毕竟,*this
是一个Derived
,尽管Base
(正确(不知道这一事实(。
对于更具体的例子,我正在编写几个类来访问 REST 服务器。 我有一个带有方法 withUrl
的 RestConnection
类,一个带有方法 withParam
和 doPost
的 PostableRest
类,以及一个带有 doGet
的GettableRest
类。 我怀疑这是不可能的,并且可能会尝试将一堆虚拟方法塞进RestConnection
但是当有多个withParam
过载时,我讨厌这样做,其中一些方法对于包含在GET参数列表中没有意义。
提前感谢!
我认为你可以在这里使用 CRTP,如下所示,其中派生类告诉基础它是什么类型:
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;
}
};
看看奇怪的重复出现的模板模式。
如果Base
是抽象类型(仅在其子类中实例化(,则使其成为采用类型名称的模板。您的Derive
将扩展模板 - 例如 Derived : public Base<Derived>
.如果 Base 是一个具体类型 - 那么你将需要引入一个新的抽象类,该类将是 Base
和 Derived
的基类型。
这样withFoo
就可以模板化以返回实际类型。
您的选项要么是 CRTP(如标记 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:
......
}
缺点是不再有一个Base
类,但尽可能多的Base
实例化是可能的派生,因此你不能再有一个 Base&or Base* 指向任何派生的东西。
如果你需要一个共同的基础来收集,你需要另一个共同基础(不是寺庙化(,基地可以从中派生。
另一种可能性是通过使 Base withFoo
虚拟来使 Base(旧的(多态。此时,在 Derived 中,您可以覆盖 withFoo 以返回 Derived&协变类型:
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)); }
...
};
这仍然包含经典的 OOP 范式,但增加了运行时开销(vtables(,并且缺点是它基于并非所有编译器都支持的功能(虚函数的协变返回类型(。
- 使用类模板的方法链接错误
- 为什么调用没有正文的纯虚拟方法不会导致链接器错误?
- 在使用库时,找到要链接的必要库的快速方法是什么
- 尝试使用 extern "C" 调用 C 中的C++方法,得到"undefined reference to"对象的链接器错误
- 将多个效果与 libSox 链接并读取输出数据的正确方法
- 当只有静态方法受到影响时,如何解决C++中的链接器错误?
- 从方法链接中使用的临时移动
- 使用 CMake 的静态方法链接错误
- 标准::字符串::空的未定义符号错误;Mac OS High Sierra 上的 c++ 标准方法链接错误
- 返回值上的 C++ 方法链接不起作用
- 方法链接中的C++执行顺序
- 将错误与静态方法链接
- 具有多态性 C++ 的方法链接
- 构造函数上的C++方法链接
- 重新加载了序列点和方法链接
- 来自命名空间的方法链接
- 方法链接导致编译错误
- 方法链接的缩进
- 垃圾回收如何处理这些由方法链接创建的静态实例
- 将内联非成员操作符的声明和定义分开的正确方法(链接器问题)