我有以下内容:
// foo.h:
class foo {
public:
foo();
~foo();
// note: the param type repetition here is only incidental, assume the
// functions can't easily be made to share type signatures
void bar(a b, c d);
void baz(a b, c d, e f, g h, i j);
void quux(a b, c d, e f, g h, i j);
private:
class impl;
impl *m_pimpl;
}
然后:
// foo.cpp:
class foo::impl {
public:
void bar(a b, c d);
void baz(a b, c d, e f, g h, i j);
void quux(a b, c d, e f, g h, i j);
private:
// lots of private state, helper functions, etc.
};
void foo::impl::bar(a b, c d) { ... }
void foo::impl::baz(a b, c d, e f, g h, i j) { ... }
void foo::impl::quux(a b, c d, e f, g h, i j) { ... }
foo::foo() : m_pimpl(new impl()) { }
foo::~foo() { delete m_pimpl; m_pimpl = NULL; }
void foo::bar(a b, c d) {
return m_pimpl->bar(b, d);
}
void foo::baz(a b, c d, e f, g h, i j) {
return m_pimpl->baz(b, d, f, h, j)
}
void foo::quux(a b, c d, e f, g h, i j) {
return m_pimpl->quux(b, d, f, h, j);
}
这里有bar
,baz
和quux
的重复次数:
foo
的声明foo::impl
的声明foo::impl
的定义foo
定义中的两次:一次用于foo
的函数参数列表,再次调用相应的foo::impl
函数。对于其中的每一个,除了最后一个我必须写出整个参数列表,其类型可以更多涉及。
在这里减少重复的最佳方法是什么?一个简单的方法是内联foo::impl
公共函数的定义,但除了设计类以外,还有什么不同的东西,以减少公共函数?
答案 0 :(得分:4)
使用签名,我们可以将其减少到3个提及,加上1组前锋:
using signature_1 = int(int);
struct foo {
signature_1 x;
foo();
~foo();
private:
struct fooimpl;
std::unique_ptr<fooimpl> pimpl;
};
int main() {
foo f;
std::cout << f.x(1) << '\n';
}
struct foo::fooimpl {
signature_1 x;
int v = 3;
};
foo::~foo() = default;
foo::foo():pimpl(new foo::fooimpl()){}
int foo::x(int y){return pimpl->x(y);}
int foo::fooimpl::x(int y){return y+v;}
如果我们的pimpl是纯虚拟类,我们可以将它降低到2 +前进。从decltype(&foo::method)
- &gt;签名写一张地图,并让纯虚拟接口使用该(和decltype)来创建纯虚拟类的签名。
在foo
中写入一次签名,decltype-在foo_impl_interface
中确定它,然后在cpp文件中的foo_impl
内内联实现。再加上一组前锋。
template<class MethodPtrType>
struct method_sig;
template<class MethodPtrType>
using method_sig_t = typename method_sig<MethodPtrType>::type;
template<class T, class R, class...Args>
struct method_sig< R(T::*)(Args...) > {
using type=R(Args...);
};
加上另外11个奇数专长(叹气)以获得所有案例。 (const&
const
const&&
const volatile
const volatile&
const volatile&&
&
&&
{{1}根据我的要求,
volatile
volatile&
限定符都是必需的。
现在volatile&&
是method_sig_t<decltype(&foo::x)>
,我们可以使用:
int(int)
假设我们使用pimpl来规范我们的类型而不是隐藏状态。
最后,不是在pimpl中实现大部分代码,而只是将STATE存储在pimpl中,而是将代码留在类中。
这会为您提供“我其他人不依赖于我的规模”:谁在关注代码是struct foo_impl_interface {
virtual method_sig_t<decltype(&foo::x)> x = 0;
virtual ~foo_impl_interface() {}
};
还是foo
的{{1}}状态?所以,如果你没有采用foo_impl
技术,为什么要转发?
答案 1 :(得分:2)
如果您的公共类只是代理调用实现,请考虑使用interface - &gt;实现模型而不是pimpl。
您只能通过用户代码中的接口来引用您的实现,class foo
是接口
class foo {
public:
virtual void bar(a b, c d) = 0;
virtual void baz(a b, c d, e f, g h, i j) = 0;
virtual void quux(a b, c d, e f, g h, i j) = 0;
virtual ~foo(){}
}
pimpl背后的理念是将私有数据和函数存储在单独的对象指针中,这样您就不会在数据存储和处理更改时破坏您的公共类接口。但它并不意味着所有代码都移动到私有对象。因此,您通常会在适当的位置实施公共功能。当公共函数 implementation 发生更改时,您不会破坏用户代码,因为您的公共函数实现将与私有类定义一起隐藏在用户之外。
答案 2 :(得分:0)
你可以这样做的一种方法是定义一个接口类,这样你就不需要重新声明所有内容并使用传递指针语义(重载operator-&gt;)
答案 3 :(得分:0)
结束这个问题:最终我认为Adrian's comment最好地解决了这个问题:“我倾向于在类定义中实现impl类的方法,这减少了一些重复。”
我上面的代码将成为:
// foo.cpp:
class foo::impl {
public:
// lots of private state, helper functions, etc.
};
foo::foo() : m_pimpl(new impl()) { }
foo::~foo() { delete m_pimpl; m_pimpl = NULL; }
void foo::bar(a b, c d) {
... code using m_pimpl-> when necessary ...
}
void foo::baz(a b, c d, e f, g h, i j) {
... code using m_pimpl-> when necessary ...
}
void foo::quux(a b, c d, e f, g h, i j) {
... code using m_pimpl-> when necessary ...
}
现在它更合理 - 只有一个用于声明,一个用于定义。将类转换为使用pimpl添加m_pimpl->
时会产生很小的开销,但是IMO这比没有重复会更烦人。