C++ 中流畅的接口和继承

发布于 2024-07-24 23:24:55 字数 768 浏览 3 评论 0原文

我想构建一个具有一些常见功能和流畅接口的基(抽象)类(让我们称之为 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();
 }

这不会编译,因为我们返回的是基类而不是 my_type。

我知道我可以:

 my_type build_my_type()
 {
    my_type ret;
    ret.with_foo().with_bar();

    return ret;
 }

但我在想如何实现它,但我没有找到任何有效的想法,一些建议?

I'd like to build a base (abstract) class (let's call it type::base) with some common funcionality and a fluent interface, the problem I'm facing is the return type of all those methods

  class base {
    public:
       base();
       virtual ~base();

       base& with_foo();
       base& with_bar();
    protected:
       // whatever...
  };

Now I could make subtypes, e.g.:

  class my_type : public base {
    public:
      myType();        
      // more methods...
  };

The problem comes when using those subtypes like this:

 my_type build_my_type()
 {
    return my_type().with_foo().with_bar();
 }

This won't compile because we're returning base instead of my_type.

I know that I could just:

 my_type build_my_type()
 {
    my_type ret;
    ret.with_foo().with_bar();

    return ret;
 }

But I was thinking how can I implement it, and I've not found any valid ideas, some suggestion?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

怂人 2024-07-31 23:25:11

我在 C# 中执行此操作的方式(我相信它也适用于 C++)是为 with_foo()with_bar() 提供默认实现...请原谅我的 c#,但是:

class base {
  virtual base with_foo()
  { throw new NotImplementedException(); }
  virtual base with_bar();
  { throw new NotImplementedException(); }
}

The way I'd do it in C#, and I believe it would work in C++ too is to provide a default implementation for with_foo() and with_bar()... Forgive my c#, but:

class base {
  virtual base with_foo()
  { throw new NotImplementedException(); }
  virtual base with_bar();
  { throw new NotImplementedException(); }
}
谜兔 2024-07-31 23:25:08

在 C++ 中,您应该返回指针或引用而不是值。 另外,您可能想解释一下“流畅的界面”的含义。

In C++ you should be returing pointers or references rather than values. Also, you might want to explain what you mean by "fluent interfaces".

满栀 2024-07-31 23:25:06

一种解决方案的工作方式如下:

return *static_cast<my_type*>(&my_type().with_foo().with_bar());

使用 static_cast 基本上告诉编译器“我知道我在这里做什么”。

One solution would work like this:

return *static_cast<my_type*>(&my_type().with_foo().with_bar());

Using static_cast basically tells the compiler 'I know what I'm doing here'.

难忘№最初的完美 2024-07-31 23:25:03

您应该返回引用/指针,并且不需要保留类型信息。

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();
}

您已经有一个虚拟析构函数。 想必您还有其他虚拟功能。 通过基类型和其中声明的虚函数访问所有内容。

You should be returning references/pointers, and you should not need to keep the type information.

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();
}

You already have a virtual destructor. Presumably you have other virtual functions. Access everything through the base type and the virtual functions declared there.

墟烟 2024-07-31 23:25:01

这个“丢失类型”的问题可以用模板来解决——但它相当复杂。

例如。

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();

This problem of "losing the type" can be solved with templates - but it's rather complicated.

Eg.

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 ...
};

You can then write

SquarePizza* p=(new SquarePizza)->withAnchovies();

The pattern is that instead of

class T : public B

you write

class T : public Fluent<T, B>

Another approach could be not to use fluent interface on the objects, but on pointers instead:

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;
  }
};

Use like this:

FluentPizzaPtr<SquarePizza> squarePizzaFactory() { ... }

FluentPizzaPtr<SquarePizza> myPizza=squarePizzaFactory().withAnchovies();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文