[英]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
typedef
或using
來實現這一點。 就像是
using FooWrapper::Impl = Foo<double>;
但這不編譯。 那么問題:
我的目標是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.