C++高级编程:构建高效稳定接口与深入对象设计技巧( 二 )


二、实现Spreadsheet方法Spreadsheet类的方法实现,如setCellAt()和getCellAt() , 只是将请求传递给底层的Impl对象:
void Spreadsheet::setCellAt(size_t x, size_t y, const SpreadsheetCell& cell) {m_impl->setCellAt(x, y, cell);}SpreadsheetCell& Spreadsheet::getCellAt(size_t x, size_t y) {return m_impl->getCellAt(x, y);}Spreadsheet的构造函数必须构造一个新的Impl以执行其工作:
Spreadsheet::Spreadsheet(const SpreadsheetApplication& theApp, size_t width, size_t height) {m_impl = make_unique<Impl>(theApp, width, height);}Spreadsheet::Spreadsheet(const Spreadsheet& src) {m_impl = make_unique<Impl>(*src.m_impl);}拷贝构造函数看起来有些奇怪,因为它需要从源Spreadsheet复制底层的Impl 。拷贝构造函数接受一个Impl的引用 , 而不是指针,所以你必须解引用m_impl指针来获取对象本身 。
Spreadsheet赋值运算符必须同样将赋值传递给底层的Impl:
Spreadsheet& Spreadsheet::operator=(const Spreadsheet& rhs) {*m_impl = *rhs.m_impl;return *this;}赋值运算符中的第一行看起来有些奇怪 。Spreadsheet赋值运算符需要将调用转发给Impl赋值运算符,这只在你复制直接对象时运行 。通过解引用m_impl指针,你强制执行直接对象赋值 , 这导致调用Impl的赋值运算符 。
【C++高级编程:构建高效稳定接口与深入对象设计技巧】swap()方法简单地交换单一数据成员:
void Spreadsheet::swap(Spreadsheet& other) noexcept {std::swap(m_impl, other.m_impl);}这种技术将接口与实现真正分离,是非常强大的 。虽然一开始有些笨拙 , 但一旦习惯了,你会发现它很自然易用 。然而,在大多数工作环境中 , 这不是常见做法,所以你可能会遇到同事的一些抵触 。支持这种做法的最有力论据不是分离接口的美学,而是如果类的实现发生变化 , 构建时间的加速 。
三、注意使用稳定的接口类,可以减少构建时间 。将实现与接口分离的另一种方法是使用抽象接口,即只有纯虚方法的接口 , 然后有一个实现该接口的实现类 。这是下个主题 。




推荐阅读