簡體   English   中英

使用預先存在的類的C ++ Pimpl Idiom

[英]C++ Pimpl Idiom using a pre-existing class

我們有一個客戶端想要訪問的高度模板化的標頭代碼庫。 例如,假設它在頭文件foo.hpp包含Foo類:

#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慣用法來包裝這個核心代碼。 具體來說,我們可以使用頭文件foo_wrapper.hpp創建一個FooWrapper類:

#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類的成員。 因此,所有操作都具有impl->genie.bar(t);形式的間接impl->genie.bar(t);

如果我們能以某種方式告訴編譯器,“實際上Impl是類Foo<double> ”會更好,在這種情況下,我們可以改為說impl->bar(t);

具體來說,我正在考慮using typedefusing來實現這一點。 就像是

using FooWrapper::Impl = Foo<double>;

但這不編譯。 那么問題:

  1. 有沒有一種很好的方法擺脫這種間接?
  2. 我應該使用更好的習語嗎?

我的目標是C ++ 11解決方案,但C ++ 14也可以。 要記住的重要一點是,解決方案不能在foo.hpp中使用頭foo.hpp foo_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;

只需使用Foo<double>

// forward declaration so that you don't need to include "Foo.hpp"
template class Foo<double>;

struct FooWrapper {
    //...
    std::unique_ptr<Foo<double>> impl;
};

// explicit template instantiation so that Foo<double> exists without distributing "Foo.hpp"
template class Foo<double>;

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM