我已經基本實現了一個提案,我的問題是,它已經完成了,如果是的話,在哪裏?和/或有更好的方式來做我在做什麼?對於這篇文章的長度感到抱歉,我不知道有更好的方式來解釋我的方法,而不是提供代碼。Pimpl框架評論/建議要求
我以前問的問題pimpl: Avoiding pointer to pointer with pimpl?
要在這裏再次解釋這個問題,基本上,可以說,我們已經有了一個接口interface
和實施impl
。此外,像pimpl成語,我們希望能夠單獨編譯impl
。
現在在C++ 0x中做到這一點的一種方法是在interface
中發出unique_ptr
指向impl
。 interface
的方法的實際實現不包括在main.cpp
中,它們分別在interface.cpp
中被單獨編譯,以及impl
的接口和實現。
我們設計這個類就好像指針不存在一樣,所以它對用戶來說是有效透明的。我們使用.
表示法調用方法,而不是->
表示法,如果我們想要複製,我們實現深度複製原理圖。
但是後來我在想如果我真的想要一個共享指針到這個pimpl。我可以做shared_ptr<interface>
,但是我有一個shared_ptr到unique_ptr,我認爲這有點傻。我可以使用shared_ptr
而不是unique_ptr
在interface
之內,但是它仍然會使用.
表示法調用函數,並且看起來不像指針,所以在淺拷貝時可能會讓用戶感到驚訝。
我開始認爲這將是很好的有一個連接的接口X
和任何兼容對X
和Y
一個對應的實現Y
一些通用的模板類,處理了大量的平普爾樣板東西。
下面是我試圖去做的。
首先,我將與main.cpp
開始:
#include "interface.hpp"
#include "unique_pimpl.hpp"
#include "shared_pimpl.hpp"
int main()
{
auto x1 = unique_pimpl<interface, impl>::create();
x1.f();
auto x2(x1);
x2 = x1;
auto x3(std::move(x1));
x3 = std::move(x1);
auto y1 = shared_pimpl<interface, impl>::create();
y1->f();
auto y2(y1);
y2 = y1;
auto y3(std::move(y1));
y3 = std::move(y1);
}
基本上這裏,x1
是標準unique_ptr
平普爾實施。 x2
實際上是一個shared_ptr
,沒有由unique_ptr
引起的雙指針。許多作業和構造函數僅用於測試。
現在interface.hpp
:
#ifndef INTERFACE_HPP
#define INTERFACE_HPP
#include "interface_macros.hpp"
class impl;
INTERFACE_START(interface);
void f();
INTERFACE_END;
#endif
interface_macros.hpp
:
#ifndef INTERFACE_MACROS_HPP
#define INTERFACE_MACROS_HPP
#include <utility>
#define INTERFACE_START(class_name) \
template <class HANDLER> \
class class_name : public HANDLER \
{ \
public: \
class_name(HANDLER&& h = HANDLER()) : HANDLER(std::move(h)) {} \
class_name(class_name<HANDLER>&& x) : HANDLER(std::move(x)) {} \
class_name(const class_name<HANDLER>& x) : HANDLER(x) {}
#define INTERFACE_END }
#endif
interface_macros.hpp
只包含這是需要我開發的框架一些樣板代碼。該接口將HANDLER
作爲模板參數,並使其成爲基類,此構造函數只是確保將事件轉發到發生操作的基地HANDLER
。當然,interface
本身不會有任何成員,也不會有任何構造函數,只是一些公共成員函數。
現在interface.cpp
是我們的其他文件。它實際上包含了interface
的實現,儘管它的名稱也是impl
的接口和實現。我不會完整列出文件,但第一個認爲它包含的是interface_impl.hpp
(對於令人困惑的命名感到抱歉)。
這裏是interface_impl.hpp
:
#ifndef INTERFACE_IMPL_HPP
#define INTERFACE_IMPL_HPP
#include "interface.hpp"
#include "impl.hpp"
template <class HANDLER>
void interface<HANDLER>::f() { this->get_impl().f(); }
#endif
注意get_impl()
方法調用。這將在稍後由HANDLER
提供。
impl.hpp
包含impl
的接口和實現。我可以分開這些,但沒有看到需要。這裏是impl.hpp
:
#ifndef IMPL_HPP
#define IMPL_HPP
#include "interface.hpp"
#include <iostream>
class impl
{
public:
void f() { std::cout << "Hello World" << std::endl; };
};
#endif
現在讓我們看看unique_pimpl.hpp
。請記住這包括在main.cpp
中,所以我們的主程序對此有定義。
unique_pimpl.hpp
:
#ifndef UNIQUE_PIMPL_HPP
#define UNIQUE_PIMPL_HPP
#include <memory>
template
<
template<class> class INTERFACE,
class IMPL
>
class unique_pimpl
{
public:
typedef IMPL impl_type;
typedef unique_pimpl<INTERFACE, IMPL> this_type;
typedef INTERFACE<this_type> super_type;
template <class ...ARGS>
static super_type create(ARGS&& ...args);
protected:
unique_pimpl(const this_type&);
unique_pimpl(this_type&& x);
this_type& operator=(const this_type&);
this_type& operator=(this_type&& p);
~unique_pimpl();
unique_pimpl(impl_type* p);
impl_type& get_impl();
const impl_type& get_impl() const;
private:
std::unique_ptr<impl_type> p_;
};
#endif
在這裏,我們將通過模板類INTERFACE
(其中有一個參數,HANDLER
,我們將在這裏填寫與unique_pimpl
),以及IMPL
類(這是在我們的例子impl
)。這個類是unique_ptr
實際所在的地方。我們正在尋找的get_impl()
函數。我們的接口可以調用此函數,以便它可以將調用轉發給實現。
讓我們來看看unique_pimpl_impl.hpp
:
#ifndef UNIQUE_PIMPL_IMPL_HPP
#define UNIQUE_PIMPL_IMPL_HPP
#include "unique_pimpl.hpp"
#define DEFINE_UNIQUE_PIMPL(interface, impl, type) \
template class unique_pimpl<interface, impl>; \
typedef unique_pimpl<interface, impl> type; \
template class interface<type>;
template < template<class> class INTERFACE, class IMPL> template <class ...ARGS>
typename unique_pimpl<INTERFACE, IMPL>::super_type
unique_pimpl<INTERFACE, IMPL>::create(ARGS&&... args)
{ return unique_pimpl<INTERFACE, IMPL>::super_type(new IMPL(std::forward<ARGS>(args)...)); }
template < template<class> class INTERFACE, class IMPL>
typename unique_pimpl<INTERFACE, IMPL>::impl_type&
unique_pimpl<INTERFACE, IMPL>::get_impl()
{ return *p_; }
template < template<class> class INTERFACE, class IMPL>
const typename unique_pimpl<INTERFACE, IMPL>::impl_type&
unique_pimpl<INTERFACE, IMPL>::get_impl() const
{ return *p_; }
template < template<class> class INTERFACE, class IMPL>
unique_pimpl<INTERFACE, IMPL>::unique_pimpl(typename unique_pimpl<INTERFACE, IMPL>::impl_type* p)
: p_(p) {}
template < template<class> class INTERFACE, class IMPL>
unique_pimpl<INTERFACE, IMPL>::~unique_pimpl() {}
template < template<class> class INTERFACE, class IMPL>
unique_pimpl<INTERFACE, IMPL>::unique_pimpl(unique_pimpl<INTERFACE, IMPL>&& x) :
p_(std::move(x.p_)) {}
template < template<class> class INTERFACE, class IMPL>
unique_pimpl<INTERFACE, IMPL>::unique_pimpl(const unique_pimpl<INTERFACE, IMPL>& x) :
p_(new IMPL(*(x.p_))) {}
template < template<class> class INTERFACE, class IMPL>
unique_pimpl<INTERFACE, IMPL>& unique_pimpl<INTERFACE, IMPL>::operator=(unique_pimpl<INTERFACE, IMPL>&& x)
{ if (this != &x) { (*this).p_ = std::move(x.p_); } return *this; }
template < template<class> class INTERFACE, class IMPL>
unique_pimpl<INTERFACE, IMPL>& unique_pimpl<INTERFACE, IMPL>::operator=(const unique_pimpl<INTERFACE, IMPL>& x)
{ if (this != &x) { this->p_ = std::unique_ptr<IMPL>(new IMPL(*(x.p_))); } return *this; }
#endif
現在很多以上只是鍋爐板代碼,做你所期望的。 create(...)
僅轉發給impl
的構造函數,否則用戶將無法看到該構造函數。還有一個宏定義DEFINE_UNIQUE_PIMPL
,我們稍後可以用它來實例化適當的模板。
現在我們可以回過頭來interface.cpp
:
#include "interface_impl.hpp"
#include "unique_pimpl_impl.hpp"
#include "shared_pimpl_impl.hpp"
// This instantates required functions
DEFINE_UNIQUE_PIMPL(interface, impl, my_unique_pimpl)
namespace
{
void instantate_my_unique_pimpl_create_functions()
{
my_unique_pimpl::create();
}
}
DEFINE_SHARED_PIMPL(interface, impl, my_shared_pimpl)
namespace
{
void instantate_my_shared_pimpl_create_functions()
{
my_shared_pimpl::create();
}
}
這可以確保所有相應的模板被編譯instantate_my_unique_pimpl_create_functions()
確保我們編譯一個0參數的創建和否則從未打算被調用。如果impl
有我們想要從main調用的其他構造函數,我們可以在這裏定義它們(例如my_unique_pimpl::create(int(0))
)。
回頭看看main.cpp
,您現在可以看到如何創建unique_pimpl
。但是,我們可以創建其他的連接方法,這裏是shared_pimpl
:
shared_pimpl.hpp
:
#ifndef SHARED_PIMPL_HPP
#define SHARED_PIMPL_HPP
#include <memory>
template <template<class> class INTERFACE, class IMPL>
class shared_impl_handler;
template < template<class> class INTERFACE, class IMPL>
class shared_pimpl_get_impl
{
public:
IMPL& get_impl();
const IMPL& get_impl() const;
};
template
<
template<class> class INTERFACE,
class IMPL
>
class shared_pimpl
{
public:
typedef INTERFACE< shared_pimpl_get_impl<INTERFACE, IMPL> > interface_type;
typedef shared_impl_handler<INTERFACE, IMPL> impl_type;
typedef std::shared_ptr<interface_type> return_type;
template <class ...ARGS>
static return_type create(ARGS&& ...args);
};
#endif
shared_pimpl_impl.hpp
:
#ifndef SHARED_PIMPL_IMPL_HPP
#define SHARED_PIMPL_IMPL_HPP
#include "shared_pimpl.hpp"
#define DEFINE_SHARED_PIMPL(interface, impl, type) \
template class shared_pimpl<interface, impl>; \
typedef shared_pimpl<interface, impl> type; \
template class interface< shared_pimpl_get_impl<interface, impl> >;
template <template<class> class INTERFACE, class IMPL>
class shared_impl_handler : public INTERFACE< shared_pimpl_get_impl<INTERFACE, IMPL> >, public IMPL
{
public:
template <class ...ARGS>
shared_impl_handler(ARGS&&... args) : INTERFACE< shared_pimpl_get_impl<INTERFACE, IMPL> >(), IMPL(std::forward<ARGS>(args)...) {}
};
template < template<class> class INTERFACE, class IMPL> template <class ...ARGS>
typename shared_pimpl<INTERFACE, IMPL>::return_type shared_pimpl<INTERFACE, IMPL>::create(ARGS&&... args)
{ return shared_pimpl<INTERFACE, IMPL>::return_type(new shared_pimpl<INTERFACE, IMPL>::impl_type(std::forward<ARGS>(args)...)); }
template < template<class> class INTERFACE, class IMPL>
IMPL& shared_pimpl_get_impl<INTERFACE, IMPL>::get_impl()
{ return static_cast<IMPL&>(static_cast<shared_impl_handler<INTERFACE, IMPL>& >(static_cast<INTERFACE< shared_pimpl_get_impl<INTERFACE, IMPL> >&>(*this))); }
template < template<class> class INTERFACE, class IMPL>
const IMPL& shared_pimpl_get_impl<INTERFACE, IMPL>::get_impl() const
{ return static_cast<const IMPL&>(static_cast<const shared_impl_handler<INTERFACE, IMPL>& >(static_cast<const INTERFACE<shared_pimpl_get_impl<INTERFACE, IMPL> >&>(*this))); }
#endif
注意create
爲shared_pimpl
實際上返回一個真正的shared_ptr
,沒有雙重重定向。在get_impl()
中的static_cast是一團糟,遺憾的是我不知道有更好的方法來做到這一點,除了繼承樹和繼承樹的兩個步驟之外。
例如,我可以想象爲其他「HANDLER」類指定入侵指針,甚至是一個簡單的堆棧分配連接,它需要以傳統方式包含所有頭文件。這樣用戶可以編寫pimpl就緒但不需要pimpl的類。
您可以從zip here下載所有文件。他們將提取到當前目錄。你需要用某些C++ 0x特性進行編譯,gcc 4.4.5和gcc 4.6.0對我來說都很好。
所以就像我說的,任何建議/意見將不勝感激,如果這已經完成(可能比我更好),如果你可以指示我,它會很好。