C++ Pimpl Idiom 使用预先存在的类

标签 c++ c++11

我们有一个客户希望访问的高度模板化的仅 header 代码库。例如,假设它包含 Foo标题中的类 foo.hpp :

#ifndef FOO_HEADER
#define FOO_HEADER

#include <iostream>

template <typename T>
struct Foo {

    Foo(){
       // Do a bunch of expensive initialization
    }

    void bar(T t){
        std::cout << t; 
    }

    // Members to initialize go here... 
};

#endif /* FOO_HEADER */

现在我们想让客户在不暴露核心代码和不重写整个代码库的情况下尝试一组精简的功能。

一个想法是使用 PIMPL 习惯用法来包装这个核心代码。具体来说,我们可以创建一个 FooWrapper标题为 foo_wrapper.hpp 的类:

#ifndef FOO_WRAPPER_HEADER
#define FOO_WRAPPER_HEADER

#include <memory>

struct FooWrapper {

    FooWrapper();
    ~FooWrapper();

    void bar(double t);

    private: 
        struct Impl;
        std::unique_ptr<Impl> impl;
};

#endif /* FOO_WRAPPER_HEADER */

和实现foo_wrapper.cpp :

#include "foo.hpp"
#include "foo_wrapper.hpp"

struct FooWrapper::Impl {
    Foo<double> genie;
};

void FooWrapper::bar(double t){
    impl->genie.bar(t);
}

FooWrapper::FooWrapper() : impl(new Impl){
}

FooWrapper::~FooWrapper() = default;

这段代码如我所料:https://wandbox.org/permlink/gso7mbe0UEOOPG7j

然而,有一件小事困扰着我。具体来说,实现需要额外的间接级别......我们必须定义 Impl类持有 Foo 的成员类(class)。因此,所有操作都具有 impl->genie.bar(t); 形式的间接寻址。 .

如果我们能以某种方式告诉编译器,“实际上 Impl 是类 Foo<double>”会更好,在这种情况下,我们可以改为说 impl->bar(t); .

具体来说,我在想一些类似 typedef 的事情或 using让这个工作。有点像

using FooWrapper::Impl = Foo<double>;

但这不编译。那么问题来了:

  1. 是否有摆脱这种间接寻址的好方法?
  2. 我应该使用更好的成语吗?

我的目标是 C++11 解决方案,但 C++14 也可以。要记住的重要一点是解决方案不能使用标题 foo.hppfoo_wrapper.hpp .我们必须以某种方式将该代码编译成一个库,并仅分发编译后的库和 foo_wrapper标题。

最佳答案

您可以在 FooWrapper.h 中前向声明 Foo。这将允许您为其声明一个 std::unique_ptr:

#ifndef FOO_WRAPPER_HEADER
#define FOO_WRAPPER_HEADER

#include <memory>

// Forward declaration
template <typename T>
class Foo;

struct FooWrapper {
  FooWrapper();
  ~FooWrapper();

  void bar(double t);

 private:
  std::unique_ptr<Foo<double>> impl;
};

#endif /* FOO_WRAPPER_HEADER */

foo_wrapper.cc:

#include "foo_wrapper.h"
#include "foo.h"

void FooWrapper::bar(double t) {
  impl->bar(t);
}

FooWrapper::FooWrapper() : impl(std::make_unique<Foo<double>>()) {}

FooWrapper::~FooWrapper() = default;

关于C++ Pimpl Idiom 使用预先存在的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55593809/

相关文章:

c# - OpenCV 程序不能在另一台计算机上运行

c++ - 在当前 Linux 发行版上打包 C++11 软件是否安全?

c++ - 缩小转换和初始化列表,哪个编译器是对的?

c++ - ffmpeg C API - 创建帧队列

c++ - 在声明 "std::vector<X> f();"中, "std::vector<X>"是实例化吗?

c++ - 一个线程结束后调用另一个线程中的方法

C++11 for_each 和 lambdas 优化

c++ - c++ 14 中的 vector<string> 或 vector<shared_ptr<string>>

c++ - 使用 QString 和 QByteArray 的 QDataStream 问题

c++ - C/C++ 中将数组作为形式参数传递为 int arr[] 和 int arr[N] 之间的区别