设计一个类是不是封装的层数太多比较好?

问题描述 投票:0回答:1

我正在阅读CPP-Concurrency-In-Action-2ed-2019这本书。在章节9.1.2中,作者给出了一个简单的例子来展示如何设计类型擦除函数的包装器:

#include <memory>
#include <utility>

class FunctionWrapper {
 public:
  FunctionWrapper() = default;

  FunctionWrapper(const FunctionWrapper&) = delete;

  FunctionWrapper& operator=(const FunctionWrapper&) = delete;

  FunctionWrapper(FunctionWrapper&& rhs) noexcept
      : impl_(std::move(rhs.impl_)) {}

  FunctionWrapper& operator=(FunctionWrapper&& rhs) noexcept {
    impl_ = std::move(rhs.impl_);
    return *this;
  }

  template <typename F>
  FunctionWrapper(F&& f) : impl_(new ImplType<F>(std::move(f))) {}

  void operator()() const { impl_->call(); }

 private:
  struct ImplBase {
    virtual void call() = 0;
    virtual ~ImplBase() = default;
  };

  template <typename F>
  struct ImplType : ImplBase {
    ImplType(F&& f) noexcept : f_(std::move(f)) {}
    void call() override { f_(); }

    F f_;
  };

 private:
  std::unique_ptr<ImplBase> impl_;
};

但我想知道是否有必要(或者换句话说,一个好的设计模式)来包装一个函数。因为一个Funciton封装成

FunctionWrapper
这么多层,比如
targer function->ImplType->ImplBase->std::unique_ptr<ImplBase>->FunctionWrapper
,然后用它到
thread_pool
就像

一样
class ThreadPool {
  ...
 private:
  ConcurrentQueue<FunctionWrapper> q_;
};

简单来说,为什么只在 FunctionWrapper 中使用

std::unique_ptr<F> impl_

c++ encapsulation
1个回答
0
投票

为什么只在 FunctionWrapper 中使用 std::unique_ptr impl_ ?

因为这不会是类型擦除。

这个类的重点是提供一个与函数的底层类型无关的相同类型。

我对这本书不熟悉,因此我使用标准类型擦除

std::function
作为示例:

  // some function
  void foo();

  std::function<void()> f;
  f = &foo;
  f = [](){};

f
可以存储各种callable。存储 lambda 的
std::function<void()>
和存储指向自由函数的指针
std::function<void()>
具有相同类型:
std::function<void()>
。只有具有不同签名的可调用对象才需要您使用不同的类型。例如,返回
int
的可调用对象可以存储在
std::function<int()>
中。

间接层并不算“太多”。这是类型擦除所需要的。粗略地说,从

ImplBase
的继承将不同类型的可调用对象之间的差异(编译时的差异)推向了虚拟调度(仅在运行时发生)。

当您对某些特定类型的可调用对象感到满意时,例如

void(*)()
,指向自由函数的指针,那么您不需要类型擦除。但是,您不能在函数指针中存储其他类型的可调用对象。例如,捕获变量的 lambda 无法转换为指向自由函数的指针。

© www.soinside.com 2019 - 2024. All rights reserved.