头文件的插入顺序
1.头文件的顺序
1.c系统文件。
2.c++系统文件。
3.其他库的.h文件。
4.本项目内的.h文件。
加入的系统的头文件使用<>。项目内的头文件使用“”。
如果编写的一个功能文件只是实现其他文件的一些接口,对其他文件的接口的一些封装,应该把这个文件的引用放在最前面。通俗的说,就是相同文件名字的头文件放在最开头。因为,当我们测试的文件中的一些接口缺少一些库的时候,或者是存在构造和语法错误的时候,当前的构造会立马停止,节约了构造的负荷,便于开发中的问题的定位。
5.在相同的规则下的头文件,按照字母的顺序来排序。
6.路径下面的使用“/”。
7.避免多重包含。
8.使用前置声明可以有效的降低编译依赖,降低模块之间的耦合性。
9.包含的文件应该使用完整的路径名字,不要使用“.”或者是“…”。
命名空间使用准则
在定义一个不需要被外部引用的变量的时候,可以把它放在匿名空间中或者是声明为static。
这些是需要在.cpp文件中声明的,这样操作的好处就是在一个文件中定义的变量和函数不可以被其他的文件引用或者是调用,即使两个文件中都完全声明了一个相同的变量和函数,他们所指向的实体是完全不同的。
匿名空间不要在.h文件中使用。
namespace {
…
} // namespace
使用静态成员函数,或者是命名空间中的的非成员函数,避免使用全裸 的全局函数。
将非成员函数放在命名空间中可以避免污染全局作用域。
将函数的变量尽量放置在最小作用域内,并在变量声明的时候进行初始化。离第一次使用越近越好。
使用初始化的方式替代先声明在赋值的方式。
静态变量的构造函数,析构函数,初始化顺序在c++并不是完全的明确的,可能随着构建的变化而变化,导致很难发现的BUG。所以禁用类的静态存储周期,同时也不容许函数的返回值来初始化原生数据类型。
同一个编译单元的初始化顺序是明确的,静态的初始化顺序优先于动态的初始化,初始化的顺序按照声明进行,销毁的时候按照构造的时候相反的顺序,但是不同的编译单元之间的构造顺序和销毁的顺序属于不明确行为。
只容许使用原生数据类型的静态变量,完全禁止vector string 类型的静态类型。
如果非要使用一个class 类型的静态数据类型,或者是全局变量。可以在main()中初始化一个全局变量指针并且永远不回收,注意只能使用raw指针,不能使用智能指针,智能指针可以自动的析构。
千万不要在循环中构造和析构。
类
1.在构造函数中可以进行各种初始化操作。
2.构造函数的地址是无法取得的,构造函数的工作无法用简单的方式交给其他的线程,
3.explicit定义于目的函数中,只有在显示的调用转换函数的之后才可以进行类型转换。单参数构造函数要加上。
4. 如果需要才容许类型支持拷贝构造函数和赋值构造函数,如果不需要就应当明确的禁止。
5. 禁用赋值操作的方式就是在类中定义然后不实现,或者在用下面的方式在构造函数的后天加上=delete。
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
6.只有在全是数据成员的情况下才使用struct,其他的情况一律使用class。
7.接口类类名以Interface为后缀,需要提供的有,带实现的虚析构函数,静态成员函数,其他的均为纯虚的函数,不定义非静态数据类型,不提供构造函数。
8.存取函数一般内联在头文件中。
9.函数体尽量短小,紧凑,功能单一。
函数
1.函数的参数顺序,1>输入,2>输入输出,3>输出。
2.所有按应用传递的参数之前必须加上const。
3.输入参数一般都是const引用,需要被修改的参数或者是输出参数一半是非const指针。
其他
1.动态分配出来的对象最好拥有单一并且固定的所有者,并且通过智能指针传递所有者。
2.智能指针不能完全的替代智能指针,智能指针的释放并不是显而易见的事情。
3.如果必须动态的分配内存,更倾向于把所有权留在分配者的手中,如果其他的地方使用这个对象,最好传递他的拷贝。或者传递一个不同改变所有权的指针或者是引用。
4.所有按应用传递的参数之前必须加上cosnt。
5.如果函数需要修改变量的值,函数的参数必须被定义为指针。
6.auto v2(std::move(v1));移动构造函数,使用类的右值引用进行构造的函数,不在进行大量的数据的复制,而是进行简单的指针操作。这将带来大幅度的性能的提升。
7.右值应用可以实现可以移动但是不可以拷贝的类型。对实际的拷贝没有用,但是需要把他们作为函数的参数传递或者塞入到容器中或者是函数参数中很有用。
8.allocator
9.允许一个类访问另一个类的私有成员的时候,使用友元。
10.如果需要在运行的时候确定类型,通常来说程序的设计存在问题。
11.虚函数可以根据子类对象的不同而执行不同的代码。这是对象本身来处理的,如果这一个行为在对象之外完成。可以考虑使用双重分发的方案。
12.使用static_cast()进行类型转换。用const_cast去掉const限定。
13.只有在记录日志的时候使用流,格式化操作符使用流处理性能是很低下的。其他的情况的话使用printf()。
14.使用前置自增,++i。
15.在任何情况下都要使用cosnt或者是constexpr。
16.如果数据成员在构造之后不再发生变化应该为其声明为cosnt,访问函数应该总是const。
17.cosntexpr用来定义真正的常量,或者实现常量的初始化。
18.使用断言来判断非负,如果需要持久化数据到磁盘上的时候需要指定系统的对齐方式。
19.
命名约定
1.文件命名全部使用小写。不要使用已经存在于include中的文件名。
2.类命名中每个单词的首字母都大写,不用下划线。
3.变量和函数的参数用小写,中间加上下划线。普通变量命名不用大小写。
4.类内数据成员最后接下划线。
5.声明为constexpr或者是const,在程序的运行期间其值保持不变的命名时候需要用k开头。大小写混合。
6.在内类定义定类型同样需要考虑的还有数据类型,比如int,char类型的,所以在命名当中不考虑使用谷歌全小写的命名方式,改用大小写混合的方式。iCount_;等dPice_。
7.在编码的时候避免使用m_开头的命名。因为m_是mfc的特性,不具有普遍的适用性。
规则特例
1.不要使用匈牙利命名规则。
2.使用原有的C++类型,比如使用const TCHAR* 而不是LPCSTR。
3.使用MS VC++进行编译的时候,警告级别设置为3级,对所有的警告当做错误处理。
4.不要使用#pragma once 而应该使用#ifndef SRC_DIR_BAR_H_,头文件的保护路径应该相对于项目的根目录。
5.使用扩展_declspec(dllimport)和_declspec(dllexport)同时需要通过宏来使用,方便在分享这些代码的时候方便的禁用。
6.使用预编译头文件,在每个文件中都加上stdafx.h,或者是precompile.h。为了代码方便的共享,避免显示的包含这些文件,使用/FI编译选项的时候可以自动的包涵这些文件。
7.资源文件通常命名为resource.h且只包涵宏。