Google开源项目风格指南-笔记

Google 开源项目风格指南——中文版

Google C++ Style Guide

1. 头文件

1.1 前置声明

        类似于函数的声明和定义,C++里类的声明和定义也是可以分开的。我们可以先声明而暂时不定义它,这种声明就称为类的前置声明。

        注意:前置声明的类是不完全类型(incomplete type),我们只能定义指向该类型的指针或引用,或者声明(但不能定义)以不完全类型作为参数或者返回类型的函数。

1.2 #include的路径及顺序

        您所依赖的符号 (symbols) 被哪些头文件所定义,您就应该包含(include)哪些头文件,前置声明 (forward declarations) 情况除外。比如您要用到 bar.h 中的某个符号, 哪怕您所包含的 foo.h 已经包含了 bar.h, 也照样得包含 bar.h, 除非 foo.h 有明确说明它会自动向您提供 bar.h 中的 symbol。不过,凡是 cc 文件所对应的「相关头文件」已经包含的,就不用再重复包含进其 cc 文件里面了,就像 foo.cc 只包含 foo.h 就够了,不用再管后者所包含的其它内容。

        在 #include 中插入空行以分割相关头文件, C 库, C++ 库, 其他库的 .h 和本项目内的 .h 是个好习惯。

3. 类

3.1 构造函数

        构造函数不得调用虚函数, 或尝试报告一个非致命错误. 如果对象需要进行有意义的 (non-trivial) 初始化, 考虑使用明确的 Init() 方法或使用工厂模式。

3.2 隐式类型转换

        在类型定义中, 类型转换运算符单参数构造函数都应当用 explicit关键字进行标记. 

        explicit:修饰只有一个参数的构造函数,以防止从参数类型到目标类类型的隐式转换

隐式类型转换,是编译器自发的行为,所以安全是第一位。所以呢,我们可以得出一条很重要的结论:

  • 隐式类型转换是从小到大的转换。在数据类型上表现是少字节数据类型,转换成多字节数据类型,保证数据的完整性;在类上表现,从子类转换成父类,保证类对象功能的正常。
  • 隐式类型转换往往是安全的,但是它可能产生意想不到的危险。
class Test
{
	public:
		Test(int i);
};

Test t1 = 1;//正确,由于强制类型转换,1先被Test构造函数构造成Test对象,然后才被赋值给t1
Test t2(1);//正确

explic关键词的用法:

class Test
{
	public:
		explicit Test(int i);
};
Test t2 = 1;//编译报错
Test t2(2);//编译没问题

3.3 拷贝构造函数 & 移动构造函数

如果你的类型需要, 就让它们支持拷贝 / 移动. 否则, 就把隐式产生的拷贝和移动函数禁用。

如果你的类不需要拷贝 / 移动操作, 请显式地通过在 public 域中使用 = delete 或其他手段禁用之.

// MyClass is neither copyable nor movable.
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;

移动构造函数: 

有时候我们会遇到这样一种情况,我们用对象a初始化对象b,后对象a我们就不在使用了,但是对象a的空间还在呀(在析构之前),既然拷贝构造函数,实际上就是把a对象的内容复制一份到b中,那么为什么我们不能直接使用a的空间呢?这样就避免了新的空间的分配,大大降低了构造的成本。这就是移动构造函数设计的初衷。

       对于指针, 

  • 拷贝构造函数中:采用深层复制;
  • 移动构造函数中:采用浅层复制。

知识点:当类中同时包含拷贝构造函数和移动构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数时,编译器才会退而求其次,调用拷贝构造函数。

3.4. 结构体 VS. 类

        仅当只有数据成员时使用 struct, 其它一概使用 class

        结构体:当定义结构体变量时,可以通过两种方式初始化它:使用初始化列表或构造函数。

3.5. 继承 

  • 使用组合通常比使用继承更适宜
  • 如果使用继承,只使用公共继承
  • 所有继承必须是public,想私有继承的话,应采取包含基类实例的方式替代
  • 如果该类有虚函数,其析构函数也应该为虚函数
  • 派生类重定义基类的虚函数时,该派生类函数也应声明为virtual函数
  • 对于重载的虚函数或虚析构函数, 使用 override, 或 (较不常用的) final 关键字显式地进行标记

C++ 11添加了两个继承控制关键字:override和final。override确保在派生类中声明的重载函数跟基类的虚函数有相同的签名。final阻止类的进一步派生和虚函数的进一步重载。

override:

        表示此虚函数必定“重写”了基类中的对应虚函数。

final:C++11的关键字final有两个用途,第一,它阻止了从类继承;第二,阻止一个虚函数的重载。

        (1) 作用在虚函数:表示此虚函数已处在“最终”状态,后代类必定不能重写这个虚函数。

        (2) 作用在类:表示此类必定不能被继承

override明确地表示一个函数是对基类中一个虚函数的重载。更重要的是,它会检查基类虚函数和派生类中重载函数的签名不匹配问题。如果签名不匹配,编译器会发出错误信息。

3.6. 多重继承

        只有当所有父类除第一个外都是 纯接口类 时, 才允许使用多重继承. 为确保它们是纯接口, 这些类必须以 Interface 为后缀. 

3.9. 存取控制

将 所有 数据成员声明为 private, 除非是 static const 类型成员 

3.10. 声明顺序

  • 将相似的声明放在一起, 将 public 部分放在最前
  • 声明次序:public -> protected -> private;
  • 在各个部分中, 建议将类似的声明放在一起, 并且建议以如下的顺序: 类型 (包括 typedefusing 和嵌套的结构体与类), 常量, 工厂函数, 构造函数, 赋值运算符, 析构函数, 其它函数, 数据成员. 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

满腹的小不甘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值