天天看点

c++101rule

组织策略

0,不拘于小结

缩进, 行的长度,命名,注释,空格,制表,

1-4,高警告级别干净利落地进行编译,使用构建系统,使用版本控制,代码审查

风格

5,一个实体应该只有一个紧凑的职责。 (依赖性管理,继承,抽象,隐藏)

6,正确简单清晰

7,

===================

01, 视c++为一个语言联邦 

multiparadigm programming langauge, 支持过程(procedrual),面向对象object oriented, 函数形式functional

,泛型形式generic, 元编程metaprogramming

02, 尽量用const 取代enumu,inline替换#define

03, 尽量用const

const成员函数目的,为了该成员函数作用于const对象身上

两个函数如果常量性不同,可以被重载

const对象大多数用于passed by poiner-to-const, passed by reference-to-const

bit constness,成员函数只有在不更改任何non-static成员对象才可以说是const,也就是说不更改对象内任何一个bit.

logical constness,一个const成员函数可以修改它所处理的对象内的某些bits,但只有客户端侦测不出的情况下才得如此。

mutable 能够释放掉non-static 成员变量的bitwise constness约束。

const char & operator[](std::size_t position) const

{

    return text[position];

}

char & operator[](std::size_t position)

    return const_cast<char&>(static_cast<const TextBlock&>)(this)[position]);

第一次转型static_cast<const TextBlock&>)(this)

第二次转换const_cast<char&>

利用const实现non const版本

反向做法不可以。const成员函数承诺不改变其对象的逻辑状态(logical state),non-const成员函数没有这样的承诺。

如果const调用non-const,就冒这样的风险:你曾经承诺不改动的那个对象被改动了。

编译器强制实施bitwise constness, 编程应该使用概念上的常量性(conceptual constness)

04, 确定对象使用前没初始化

变量初始化规则,取决于变量类型和位置

1)内置类型变量初始化取决于变量定义的位置,函数体外定义的变量都初始化成0,函数体里定义的内置类型不进行自动

初始化。

2)类类型变量的初始化,通过构造函数初始化(有默认/无默认需要显示调用)

non-local-static 对象初始化顺序无法确定

对应内置对象手工初始化

使用成员初始值列表,不要在构造函数里面赋值,免除“跨编译单元之初始化次序”问题,用local static 对象替换

non-local static对象

05,了解c++默认编写哪些函数

default构造函数,拷贝构造函数,拷贝赋值

06,若不使用编译器自动生成的函数,就该明确拒绝。

uncopable 将构造函数声明为private

07,为多态声明virtual 析构函数

08,别让异常逃离析构函数

09, 绝不在构造函和析构过程中调用virtual函数

可以用private static函数,作为辅助函数给base calss构造函数传值。

10, 另operator= 返回一个reference to *this

连锁赋值。这只是个协议,无强制性。内置标准类型和标准库都提供

11,在Operator= 中处理自我赋值

确定任何函数如果操作一个以上对象,其中多个对象是同一个对象时,执行仍然正确。

12, 复制对象时勿忘其每一个成分

1)复制local成员变量,2)base class内的coppying函数

copy assignment调用copy构造函数是不合理的。因为这就像试图构造一个已经存在的对象。

copy构造函数调用copy assignment操作同样无意义。 构造函数用来初始化新对象,而assginment

操作只实施于已经初始化的对象上。对一个尚未构造好的对象赋值,就像在一个尚未初始化的对象上

做“只对已经初始化对象才有意义”的事情一样。

如果你发现copy构造函数和copy assignment操作符有相近的代码,消除重复代码的做法是,

建立一个新的成员函数给两者调用。这样的函数往往是priviate,而且常命名init.

1)copy函数应该确保复制对象内的所有成员变量及base成分

2)不要尝试以某个copying函数实现另一个copying函数。应该将共同机能放在第三个函数中,

并由copying函数共同调用。

资源管理

文件描述符,互斥锁,图像界面字体笔刷,数据库,socket

13, 以对象管理资源

获得资源后立刻放进管理对象auto_ptr RAII resource acquisition is initialization

管理对象运用析构函数确保资源释放

RCSP reference-couting smart pointer RCSP无法打破环状引用。

tr1::shared_ptr就是RCSP

为了防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源

两个常被使用的RAII classes分别是tr1_shared_ptr和auto_ptr

14, 在资源管理类中心小心copying行为

15,在资源类中提供对资源的访问

RAII class 应该提供取得其管理之资源的办法

对原始资源的访问可能经由显示转换或隐士转换,一般而言显示转换比较安全,隐士转换对客户比较

方便

16,对使用new和delete要采用相同的形式

delete pal; delete [] pal;

17,以独立newed对象需要置入智能指针

以独立语句将Newed对象置于智能指针内,如果不这样,一旦异常抛出,有可能导致难以觉察的资源泄漏

设计与声明

18,让接口容易被正确使用,不容易被误用

理想上,如果客户企图使用某个接口却没有获得他所预期的行为,这个代码不应该通过编译,反之则是

客户想要的

接口一致性。尽量与内置types一致。

限制类型内什么事可以做,什么不可以做,常用const限制。

防止误用,包括建立新类型,限制类型上的操作,束缚对象值,消除客户端资源管理责任

tr1::shared_ptr支持定制删除器,可以防范DLL问题,可被用来自动解除互斥锁。

19 设计class犹如设计type

重载函数,操作符,控制内存分配,定义对象初始化终结。

新type的对象应该如何被创建销货

对象的初始化和对象的赋值应该有什么样的差别。这个答案决定构造函数和赋值操作符的行为

新type对象如果被passed by value,意味着什么? copy构造函数

什么是typed的合法值。 class约束条件 invariants.

你新type需要配合某个继续体系图么?

你的type需要什么样的转换?

什么样的函数对新type而言合理,memeber函数

什么样的标准函数应该驳回, private函数

谁该取用新type成员。public成员

什么是新type的未声明接口

你的新type有多么一般化 class template

你需要一个新type么?

20,宁以pass-by-reference-to-const 替换pass-by-value

防止产生副本copy构造函数多次调用

防止对象切割,子类被视为基类对象传递

这个规则不适用于内置类型

21, 必须返回对象时,别妄想返回其reference.

绝不要返回Pointer或reference指向一个local stack对象,或返回reference指向

一个heap-allocated对象,返回pointer或reference指向local static对象有可能

同时需要多个这样的对象。

22,将成员变量声明为private

23,宁以non-member ,non-friend替换member函数

数据以及操作数据的那些函数应该捆绑到一块。

如果某些东西被封装,它就不再可见。愈多东西被封装,愈少人可以看到它。而遇少

人看到它,我们就有愈大的弹性去变化它。因为我们改变仅仅直接影响看到改变的那些

人和事物。因此,愈多东西被封装,我们改变那些东西的能力就愈大。封装使我们改变

事物只影响有限客户。

限制考虑对象数据,愈少代码可以看到数据(也就是访问它),愈多的数据可以被封装

,而我们也就遇能自由地改变对象数据,例如改变成员变量的数量,类型等等。如何测量

“有多少代码可以看到一块数据”,我们计算能访问该数据的函数,作为一种粗糙的测量。

愈多函数访问它,数据的封装性愈低。

名字空间可以跨多个源文件,类不能,类是一个整体不能分割。

prefer non-member non-friend to member,这样做增加封装性,包裹弹性,和机能扩充性。

24,若所有参数皆需类型转换,请为此采用non-member函数

只有参数被列入参数列,这个参数才是隐式类型转换的合格参与者。

member的函数反面是non-member,而不是friend.

不能够只因为不该成为member,就自动让它成为friend.朋友带来的麻烦往往过于其价值。

25,考虑写出一个不抛出异常的swap函数。

无法偏特化function template.只能对class template偏特化。

可以重载function template

std::swap 典型实现

namespace std {

  template<typename T>

  void swap(T& a, T&b)

  {

    T temp(a);

    a = b;

    b = temp;

  }

如果不赋值,只想拷贝指针pimp.可以对std::swap特化,下面是基本构想,但目前无法通过编译

namespace std{

  template<> void swap<Widget>(Widget &a, Widget& b)

    swap(a.pmpl, b.pmpl);

在Wiget类中加一个成员swap函数,这种做法同STL容器一致。

class Widget {

  public:

    void swap(Widget & other)

    {

      using std::swap;

      swap(pImpl, other.pImpl);

    }

};

如果类Widget 和 WidgetImp是模板

template<T>

class WidgetImp {...};

class Widget{...};无法在std内添加重载模板,违反标准。

namespace WidgetStuf

  ...

  class Widget {...};

  void swap(widget<T> a, widget<T>b)

    a.swap(b);

如果打算置换两个widget对象,根据c++名字查找法则 name lookups rules. argument-dependent lookup或koening lookup法则

pimp pointer to implementation.

本文转自莫水千流博客园博客,原文链接:http://www.cnblogs.com/zhoug2020/p/6055074.html,如需转载请自行联系原作者

继续阅读