【问题标题】:adapter class for C++ interface with move constructor带有移动构造函数的 C++ 接口的适配器类
【发布时间】:2016-10-28 12:46:19
【问题描述】:

我正在尝试为接受 a) 接口的实现的接口类编写一个adapter 类,该接口应该是堆栈分配的(因此不需要从外部进行新/删除处理,适配器本身可以使用 new/delete) 和 b) 将由接口的相应实现调用的 lambda 函数。

#include <iostream>
#include <functional>

struct interface {
  virtual int hello() = 0;
};

struct implementation : public interface {
  virtual int hello() {
    std::cout << "hello()\n";
    return 42;
  }
};

struct adapter {
  interface* obj;

  adapter(std::function<int()>&& func) {
    struct lambda : public interface {
      std::function<int()> func;
      lambda(std::function<int()> func_): func(func_) { }
      virtual int hello() {
        return this->func();
      }
    };
    this->obj = new lambda{func};
  }

  adapter(interface&& impl) {
    // TODO: pretty sure that's incorrect
    //       but can I somehow create a copy of "impl" on the heap?
    this->obj = &impl;
  }
};

int main() {
  adapter a([]() { std::cout << "hello from lambda\n"; return 99; });
  a.obj->hello();

#if 0
  // ERROR
  adapter b(implementation());
  b.obj->hello();
#endif
  return 0;
}

这是我在启用adapter b 部分时遇到的错误。

prog.cpp: In function 'int main()':
prog.cpp:39:4: error: request for member 'obj' in 'b', which is of non-class type 'adapter(implementation (*)())'
  b.obj->hello();
    ^
  1. 我完全不理解错误,非常感谢您的解释
  2. 我怎样才能真正正确地实现adapter(interface&amp;&amp;) 构造函数?我可能需要在堆上创建对象的副本,否则在adapater 构造函数之后它不会持久化

在 ideone 上测试:http://ideone.com/Gz3ICk 使用 C++14 (gcc-5.1)

PS:是的,adapter 类缺少一个析构函数,该析构函数应该删除从 lambda 构造函数创建的 obj

【问题讨论】:

  • 您需要一个“虚拟复制构造函数”来复制多态基类(这是一个虚拟克隆函数)。
  • @DieterLücking 好的,我希望可以在没有虚拟复制功能的情况下以某种方式复制右值。 interface const&amp; 而不是 interface&amp;&amp; 可能是同样的情况?使用虚拟复制功能会破坏我的目标设计。

标签: c++ c++11 interface move-semantics object-lifetime


【解决方案1】:

试试

adapter b {implementation()};

问题是

adapter b(implementation());

没有被解释为(如果我没记错的话)为adapter 类型的对象的实例化,而是被解释为名称为b 的函数的声明接收@987654325 类型的对象@ 接受一个(未命名的)参数,它也是一个函数,返回类型实现并且不接受任何参数[宋元瑶更正]并返回一个adapter

我知道解决这种歧义的两种解决方案

1) 添加一对括号

adapter b((implementation()));

2) 使用基于大括号的新统一初始化样式

adapter b {implementation()};

我建议使用表格 2,因为您使用 C++11 和(恕我直言)它更清晰。

---增加了解决寿命问题的例子---

要解决impl 的复制/克隆/生命周期问题,嗯...您正在使用指向纯虚拟基类的指针;我看到的唯一解决方案是克隆派生类。

我提出了一个解决方案

1) 将 adapter 中的 objinterface * 切换到 std::unique_ptr&lt;interface&gt;(以避免释放问题)

2) 在interfece 中添加了一个纯虚拟成员clone(),它返回一个std::unique_ptr&lt;interface&gt;

3) 添加了一个中间模板类(interHelper),只实现一次clone()

以下是我提出的解决方案

#include <memory>
#include <iostream>
#include <functional>

struct interface
 {
   virtual int hello() = 0;
   virtual std::unique_ptr<interface> clone () const = 0;
 };

template <typename D>
struct interHelper : public interface 
 {
   std::unique_ptr<interface> clone() const override
    { return std::unique_ptr<interface>(new D((const D &)(*this))); }
 };

struct implementation : public interHelper<implementation>
 {
   int hello() override
    {
      std::cout << "hello()\n";
      return 42;
    }
 };

struct adapter
 {
   struct lambda : public interHelper<lambda>
    {
      std::function<int()> func;

      lambda (std::function<int()> func_): func(func_)
       { }

      int hello() override
       { return this->func(); }
    };

   std::unique_ptr<interface>  obj;

   adapter (std::function<int()>&& func) : obj { lambda{func}.clone() }
    { }

   adapter (interface&& impl) : obj { impl.clone() }
    { }
 };

int main()
 {
   adapter a([]() { std::cout << "hello from lambda\n"; return 99; });

   a.obj->hello();

   adapter b { implementation() };

   b.obj->hello();

   return 0;
 }

p.s.:对不起我的英语不好

【讨论】:

  • 它有效,谢谢。你能向我解释为什么这有效吗?并且由于implementation() 的生命周期,adapter 构造函数中的&amp;impl 的地址是否无效?
  • “接收类型实现的对象”不正确。它接受一个(未命名的)参数,它也是一个函数,返回类型 implementation 并且不接受任何参数。
  • @songyuanyao - 行动!你说得对;更正;谢谢。
  • @NiklasR - 我没有看到解决impl 问题生命周期的优雅解决方案;但我已经修改了我对一个比没有更好的解决方案的答案;希望这会有所帮助
  • 感谢您的解释和解决生命周期问题的示例!没错,这不是一个优雅的解决方案,我将不得不花一些时间思考它是否值得麻烦,或者只是要求接口的用户将实现传递为new implementation
猜你喜欢
  • 2015-06-30
  • 1970-01-01
  • 2017-09-19
  • 1970-01-01
  • 1970-01-01
  • 2013-11-05
  • 2020-08-25
  • 1970-01-01
  • 2011-05-22
相关资源
最近更新 更多