C++ 中的流利接口和继承
Posted
技术标签:
【中文标题】C++ 中的流利接口和继承【英文标题】:Fluent interfaces and inheritance in C++ 【发布时间】:2009-06-24 22:28:30 【问题描述】:我想构建一个具有一些通用功能和流畅接口的基础(抽象)类(我们称之为type::base
),我面临的问题是所有这些方法的返回类型
class base
public:
base();
virtual ~base();
base& with_foo();
base& with_bar();
protected:
// whatever...
;
现在我可以制作子类型了,例如:
class my_type : public base
public:
myType();
// more methods...
;
使用这样的子类型时会出现问题:
my_type build_my_type()
return my_type().with_foo().with_bar();
这不会编译,因为我们返回的是 base 而不是 my_type。
我知道我可以:
my_type build_my_type()
my_type ret;
ret.with_foo().with_bar();
return ret;
但我在想如何实现它,我没有找到任何有效的想法,一些建议?
【问题讨论】:
我已经删除了命名空间的东西,因为它与问题无关(据我所知) 【参考方案1】:这个“丢失类型”的问题可以通过模板来解决——但是相当复杂。
例如。
class Pizza
string topping;
public:
virtual double price() const;
;
template <class T, class Base>
class FluentPizza : public Base
T* withAnchovies() ... some implementation ... ;
;
class RectPizza : public FluentPizza<RectPizza, Pizza>
double price() const return length*width; :)
;
class SquarePizza : public FluentPizza<SquarePizza, RectPizza>
... something else ...
;
然后你就可以写了
SquarePizza* p=(new SquarePizza)->withAnchovies();
模式是,而不是
class T : public B
你写
class T : public Fluent<T, B>
另一种方法是不在对象上使用流式接口,而是在指针上使用:
class Pizza ... ;
class RectPizza ... ;
class SquarePizza ... whatever you might imagine ... ;
template <class T>
class FluentPizzaPtr
T* pizza;
public:
FluentPizzaPtr withAnchovies()
pizza->addAnchovies(); // a nonfluent method
return *this;
;
这样使用:
FluentPizzaPtr<SquarePizza> squarePizzaFactory() ...
FluentPizzaPtr<SquarePizza> myPizza=squarePizzaFactory().withAnchovies();
【讨论】:
您能举个例子吗?这可能很有趣。 参见。编辑。这可能很有趣,我不知道我是否会亲自使用它... 所以你实际上切换到指针。然后你可以只使用简单的多态性,不使用 CRTP,并返回 base*。 你可以想象那里的引用(如果你不想要指针)。我只是不会让这些方法总是返回一个副本,但这不是核心问题。 CRTP 的主要目的是消除对 base(或 base* 或 base&)的衰减,这是我认为您希望避免的。 如果您要返回指针或引用,请返回 static_cast您应该返回引用/指针,并且您不需要保留类型信息。
class base
public:
base();
virtual ~base();
base &with_foo();
base &with_bar();
protected:
// whatever...
;
class my_type : public base
public:
my_type();
// more methods...
;
base *build_my_type()
return &new my_type()->with_foo().with_bar();
您已经有一个虚拟析构函数。大概您还有其他虚拟功能。通过基类型和在那里声明的虚函数访问所有内容。
【讨论】:
问题是我不想丢失类型。【参考方案3】:一个解决方案可以这样工作:
return *static_cast<my_type*>(&my_type().with_foo().with_bar());
使用static_cast
基本上告诉编译器'我知道我在这里做什么'。
【讨论】:
【参考方案4】:在 C++ 中,您应该返回指针或引用而不是值。此外,您可能想解释一下“流畅的界面”是什么意思。
【讨论】:
抱歉——我一看到“Martin”这个名字,我的bullsh*t 检测器就以最大音量熄灭,我无法再阅读了。无论是名字还是姓氏,似乎都没有关系。【参考方案5】:我在 C# 中执行此操作的方式,并且我相信它也可以在 C++ 中工作,是为 with_foo()
和 with_bar()
提供默认实现...原谅我的 c#,但是:
class base
virtual base with_foo()
throw new NotImplementedException();
virtual base with_bar();
throw new NotImplementedException();
【讨论】:
但这并不能解决问题 - 问题是类型不匹配,与问题无关。以上是关于C++ 中的流利接口和继承的主要内容,如果未能解决你的问题,请参考以下文章