跳到内容

C++ 编程/习惯用法

来自维基教科书,开放的书籍,开放的世界

习惯用法

[编辑 | 编辑源代码]

在赋值运算符中处理自我赋值

[编辑 | 编辑源代码]

T::operator=处理 LHS 和 RHS 指向同一个对象的情况。

T& operator= (const T& that)
{
    if (this == &that)
        return *this;

    // handle assignment here

    return *this;
}

笔记

  • 请记住 *标识*(LHS 和 RHS 是同一个对象)和 *相等*(LHS 和 RHS 的值相同)之间的区别。T::operator=必须保护自己免受 *标识* 的影响,因为在那种情况下,赋值代码可以方便安全地假设 LHS 和 RHS 指向不同的对象。
  • 还有其他更优秀的技术,但并非在所有情况下都适用。例如,如果类的所有成员T(比如,mem1, mem2, ..., memN)提供一个swap函数,可以使用以下代码代替
T& operator= (T that)
{
    // that is constructed by the copy constructor

    mem1.swap (that.mem1);
    mem2.swap (that.mem2);

    ...

    memN.swap (that.memN);

    // now what were originally this->mem1, this->mem2, etc. get
    // destroyed when that gets destroyed, and that.mem1, etc. are
    // retained in *this 

    return *this;
}

指向实现的指针 (pImpl)

[编辑 | 编辑源代码]

“指向实现的指针”(pImpl)习惯用法,也称为“不透明指针”习惯用法,是一种为类提供数据并因此进一步实现抽象的方法。

在 C++ 中,您必须在类定义中声明成员变量,然后该变量是公开的,并且这是必要的,以便为其分配适当的内存空间,这意味着在“所有”类中都不可能实现抽象。

但是,以额外的指针解引用和函数调用为代价,您可以通过指向实现的指针获得这种级别的抽象。

class Book
{
public:
  void print();
private:
  std::string  m_Contents;
}

所以,使用 Book 类的人只需要了解 print(),但是如果您想为 Book 类添加更多细节,会发生什么。

class Book
{
public:
  void print();
private:
  std::string  m_Contents;
  std::string  m_Title;
}

现在所有使用 Book 类的人都需要重新编译,因为他们知道的那个对象变得更大了,但他们仍然只调用 print()。

pImpl 将实现以下模式,这样就不会出现这个问题。

/* public.h */
class Book
{
public:
  Book();
  ~Book();
  void print();
private:
  class BookImpl;
  BookImpl* const m_p;
}

并在一个单独的“内部”头文件中

/* private.h */
#include "public.h"
#include <iostream>
class Book::BookImpl
{
public:
  void print();
private:
  std::string  m_Contents;
  std::string  m_Title;
}

然后 Book 类的主体将类似于

Book::Book(): m_p(new BookImpl())
{
}

Book::~Book()
{
  delete m_p;
}

void Book::print()
{
  m_p->print();
}

/* then BookImpl functions */

void Book::BookImpl::print()
{
  std::cout << "print from BookImpl" << std::endl;
}

然后从 main 函数调用

int main()
{
  Book b;
  b.print();
}

您也可以使用 std::unique_ptr<BookImpl> 或等效项来管理内部指针。

进一步阅读

[编辑 | 编辑源代码]
华夏公益教科书