C++规范

C++规范

让自己习惯C++

条约1:视C++为一个语言联邦

c++目前是一个多重泛型编程语言,支持过程式,对象式,函数式,泛型式,元编程式.这是一个语言联邦

  • C part of C++: C++以C为基础
  • class part of C++,c with class
  • template part of C++,C++泛型编程
  • stl part of C++ 标准模板库template的程序库,对容器,迭代器,算法,函数对象有规约与配合协调

条约2:尽量以const,enum,inline代替 #define

  • 使用const常量替代宏常量
  • 使用enum,使数字成为记号
  • 使用inline代替宏函数

条约3:尽可能使用const

  • const 变量 将某些东西声明const 可以让编译器侦测错误用法,const 可以被施加于任何作用域内的对象,函数参数,函数返回类型,成员函数本体
  • 编译器强制实行 bitwise constness 但你便携程序应使用概念上的常量性.
  • const 和non-const 成员函数有实质等价的实现时,令non-const调用const可以避免代码重复

构造/析构/赋值运算

条约4:确定对象被使用前已被初始化

  • 为内置型对象手动初始化,C++并不保证初始化它们

  • 构造函数最好使用成员初始列,而不要在构造函数本体内使用赋值操作,初值列出的成员变量,排序次序应该与其class声明次序相同

  • 为避免跨编译单元初始化次序问题,请以局部静态变量替换非局部静态变量

条约5:了解C++默默编译并调用了哪些函数

空类在C++编译时会声明一个拷贝构造函数,一个拷贝操作符,一个构造函数,一个析构函数,且都为内联函数

条约6:如果不想使用编译器自动生成的函数,就应当明确拒绝

比较优美的方式,是将拷贝构造函数,一个拷贝操作符声明在private环境下,这极大程度的限制了他人调用这种默认函数

毕竟你希望它是独一无二的,更优美的做法是,将其写入基类,再继承,在生成一个类,这样就可以在编译期看到错误

  • p驳回编译器暗自提供的机能,可将对应的成员函数声明为private并不予实现,使用uncopyable这样的基类也是一种做法

条约7:为多态基类声明virtual析构函数

  • 具有多态性质的基类,应当声明虚拟析构函数,如果类带有任意虚拟函数,就应当具备虚拟析构函数
  • 类如果涉及目的不是作为基类使用,或不具备多态性,就不应该声明虚拟析构函数

条约8:别让异常逃离析构函数

  • 析构函数绝对不要吐出异常,如果析构函数调用可能抛出异常,析构函数应该捕捉任何异常,并吞下它们或结束程序
  • 如果客户需要对某个操作函数运行期间抛出异常做出反应,那么class应该提供一个普通构造函数执行该操作,而不是执行该操作

条约9:绝不在构造和析构过程中调用virtual函数

  • 析构与构造期间不要调用虚拟函数,因为此类调用从不下降至派生类,

条约10:令operator = 返回一个ref to *this

  • operator = 应返回自己的首地址,a = b = c 采用右结合律,即a = (b = c ),且此条约只是协议,并不强制,但该条约被所有内置类型与stl库l类型(如vector,dequeue,string)所共同遵守,除非你有一个标新立异的好理由,不然还是随众吧

条约11:在 operator = 中处理自我赋值

  • 潜在风险为 a[i] = a[j],当i=j 时,或者 *px = *py,当px,py指向同一个对象

  • 确保当对象自我赋值时operate= 有良好的行为,其中技术包括"来源对象"和"目标对象"的地址,精心周到的语句顺序,以及copy and swap

  • 确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为任然正确

条约12:复制对象时勿忘记每个成分

  • 你需要首先调用基类的拷贝构造函数,再将自己的每个成员变量都拷贝出去才可以
  • 不要尝试在一个拷贝函数中实现另一个拷贝函数,而应该将其共同的机能放在第三个函数中,并由两个拷贝函数共同调用

资源管理

条约13:以对象管理资源

  • 你需要首先调用基类的拷贝构造函数,再将自己的每个成员变量都拷贝出去才可以
  • 不要尝试在一个拷贝函数中实现另一个拷贝函数,而应该将其共同的机能放在第三个函数中,并由两个拷贝函数共同调用

条约14:在资源管理类中小心copy 行为

  • 复制RAII对象必须一并复制他所管理的资源,所以资源的拷贝行为决定RAII对象的拷贝行为
  • 普遍常见的RAII类拷贝行为为:抑制拷贝,施行引用计数法,其他行为也可能被实现

条约15:在资源管理类中提供对原始资源的访问

隐式转换

operator FontHandle() const{return f;}

  • apis 往往要求访问原始资源(raw resources),所以每一个RALL class 应该提供一个取得其所管理资源的办法
  • 对原始资源访问可能经由显式转换或隐式转换,一般而言显式转换比较安全,但隐式转换对客户比较方便

条约16:成对使用new 和delete 时要采取相同形式

  • 如果在new 表达式使用[],那么在delete 中也要使用[].如果不使用,那么delete中也不得使用

条约17:以独立语句将newed 对象置入智能指针

  • 以独立语句将newed 对象存储于智能制造内,如果不这么做,一旦一场抛出,可能造成难以察觉的内存泄露

设计与声明

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

  • 好的接口很容易被正确使用,不容易被误用,你应该在你的所有接口中努力达成这些性质
  • 促进正确使用 的办法包括接口的一致性,以及与内置类型的行为兼容
  • 阻止误用 的办法包括建立新类型,限制类型上的操作,束缚对象值,以及消除客户的资源管理责任
  • tr1::shared_ptr支持定制类型删除器,这可防范dll 问题,可被用来自动解除互斥锁

条约19:设计class犹如设计type

  • 新type 的对象应该如何被创建与销毁,这回影响你的class构造函数与析构函数以及内存分配函数与释放函数,当然前提是如果你打算撰写他们
  • 对象的初始化与对象赋值应该有什么样的差别,者会影响到你class 的构造函数与赋值函数操作符的行为,以及者期间的差异,很重要的是别混淆了初始化与赋值,因为它们对于不同的函数调用
  • 新type 的对象如果被passed by value(值传递),意味着什么,记住,拷贝构造函数用来定义一个type 的passed by value 该如何实现
  • 什么是新 type 的“合法值”?对 class 的成员变量而言,通常只有某些数值集是有效的。那些数值集决定了你的 class 必须维护的约束条件(invariants),也就决定了你的成员函数(特别是构造函数、赋值操作符和所“setter”函数必须进行的错误检查工作。它也影响函数抛出的异常、以及(极少被使用的)函数异常明细列(exception specifications)
  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值