1禁止在头文件中定义变量
2禁止在extern “C”中包含头文件,否则会导致extern “C”嵌套,嵌套太多导致编译错误
3每个模块提供多个.c文件,在同一目录下,目录名为模块名,并提供一个.h文件
4.如果一个模块包含多个模块,则每个模块提供一个.h文件名为子模块名
5.头文件排版方式:1.按字母升序
2.将不稳定(常修改)的放在前面
6.一个函数仅完成一项功能。重复代码尽量写成函数
7.避免函数过程,最好不超过50行。
8.代码嵌套不超过4层
9.函数不变参数要写为const
10.避免使用全局变量和静态变量
11.函数参数个数不超过5个。检查参数的有效性(是否为NULL)
12.命名规则
l unix风格:每个单词小写,并用下划线分开my_name
l windows风格:每个单词首字母大写 MyName
l 文件命名采用小写字符
l 全局变量g_ 静态变量s_
(5)宏:大写单词_大写单词
13:将宏定义的放在大括号内
14:用const替代宏定义
15.inline函数的优点:
l 编译时不用展开,代码Size小,
l 可以加断电,易于定位问题。例如对于引用计数加减的时候
l 编译时编译器做语法检查
16.注释在代码上面(用空行隔开)或右边
17
文件头注释:
/**
*@file 文件名
*@brief 功能描述
*@version 版本
*@author 作者
*@date 创建日期
*/
函数头注释:
/**
*@descriotion
*@param a
*@param b
*@return c
*/
18程序块采用缩进风格编写,每级缩进为4个空格。
19相对独立的程序块之间、变量说明之后必须加空行
20.一条语句不能过长,拆分
l 换行时要增加一级缩进
l 低优先级操作符处划分新行;换行时操作符应该放下来放在新行首
l 换行时一个完整的语句放在一行
l 一行只写一条语句
21.两个以上的关键字、变量、常量进行对等操作时,操作符前后应该加空格
l 符号、操作符后面加空格
l if、for、while、switch后加空格。
l !、~、++、--、&后不加空格
l 注释符与注释内容之间加空格
22一组相关的整数用enum
23.不相关的常量,即使取值相同,也必须分别定义
24变量使用时才声明并初始化
25.避免构造函数做复杂的初始化,
可以使用init函数():
l 需要提供初始化返回信息
l 数据成员初始化可能抛异常
l 数据成员初始化失败会造成该类对象初始化失败,引起不确定状态
l 数据成员初始化依赖this指针:构造函数没结束,对象就没有构造出来,构造函数内不能使用this成员
l 数据初始化需要调用虚函数。在构造函数和西沟函数中调用虚函数,会导致未定义行为。
26初始化列表严格按照成员声明顺序初始化
27.使用c++风格的类型转换
const_cast 移除const属性的转换。避免使用
dynamic_cast下行转换,基类指针转换为子类指针。类型检查,建议调试代码中使用
static_cast 一般的强制转换
reinterpret_cast 转换不相关的类型,避免使用。
28.内联函数小于10行。且不要有循环、递归、虚函数。内联函数在头文件中声明
29.尽量用const引用取代指针。引用比指针安全,一定非空,一定不会指向其他目标。不需要检查非法NULL指针
30,一定要写构造函数。
构造函数参数列表的初始化
Message():
a(0),
b(“”),
c(NULL)
{
}30.如果不定义构造、拷贝、赋值、析构等。编译器会自动生成。
默认的构造和赋值函数只是将元对象的成员简单赋值给目的对象,即浅拷贝(shallow copy)。使元对象和目的对象的成员指向同一内存,导致资源重复释放。自动生产的析构函数是空的,不能释放已盛情的堆内存。如果不需要拷贝够咱函数和赋值函数,将其声明为private
31..让operator=返回*this的引用,使之能连等。并检查是否是自赋值
String&String::operator=(const String &rhs)
{
If(this!=&rhs)
{
delete [] data;
data=new char[strlen(rhs.data)+1];
strcpy(data,rhs.data);
}
return *this;
}
32基类指针执行删除操作时,基类的析构函数设为共有虚拟的。保障派生类析构函数被调用
33虚函数不使用默认参数,因为是动态绑定的,而默认参数是编译时静态绑定的,所以最终执行的函数是一个定义在派生类,但却使用了基类的默认参数值的虚函数
class A
{
public:
virtual void display(const string& str="Base")
{
cout<<str<<endl;
}
};
class B:public A
{
public:
virtual void display(const string& str="Derived")
{
cout<<str<<endl;
}
};
A* a=new B();
a->display();//调用派生类display,调用基类默认形参,输出Base,
delete a;
a=NULL;
34.绝不重新定义(隐藏)继承而来的非虚函数。因为无法动态绑定
35.避免派生类中定义与基类同名但参数类型不同的函数,引起虚函数调用失败
36.派生类重定义的虚函数也要声明virtual
37.仅在输入参数类型不同个,功能相同时重载函数
38建议4.7 使用重载以避免隐式类型转换
说明:隐式转换常常创建临时变量;如果提供类型精确匹配的重载函数,不会导致转换。
示例:
class String
{
//…
String( const char* text ); //允许隐式转换
};
bool operator==( const String&, const String& );
//…代码中某处…
if( someString == "Hello" ) {... }
上述例子中编译器进行隐式转换,好像someString == String( "Hello")一样,形成浪费,因为并不需
要拷贝字符。使用操作符重载即可消除这种隐式转换:
bool operator==( const String& lhs, const String& rhs ); //#1
bool operator==( const String& lhs, const char* rhs ); //#2
bool operator==( const char* lhs, const String& rhs ); //#3
39使用名字空间进行归类,避免符号冲突cout<<space_a::a+space_b::a;
40不要在头文件中或者#include之前使用using指示符
41不要在extern "C"内部使用#include包含其他头文件
在C++代码中调用C的库文件,需要用extern "C"来告诉编译器:这是一个用C写成的库文件,用C的方式来链接它们。
严格的讲,只应该把函数、变量以及函数类型这三种对象放置于extern "C"的内部。
如果把#include指令放在extern "C"里面,可能会导致extern "C"嵌套而带来如下几个风险:
extern "C"嵌套过深,导致编译错误
extern "C"嵌套后,改变其他某些文件的编译链接方式
42构造函数初始化列表在同一行或按4格缩进并排几行
43类的声明按照一定的次序和规范进行。建议的次序如下:
按照存取控制特性段排序:public、protected、private,如果没有可以忽略。这个排序是让声
明的时候使用者首先看到最关心的特性(对外接口)。
在每一段中按照如下顺序声明(先定义后续用到的类型,常量和enums;然后定义行为(构造,析构,
成员函数),最后定义成员变量):
1. typedefs和enums;
2. 常量;
3. 构造函数;
4. 析构函数;
5. 成员函数,含静态成员函数;
6. 数据成员,含静态数据成员。
44 使用‘//’注释方式,而不是‘/* */',容易产生交叉错乱
45不直接使用C++的基本数据类型,不要假定其存储尺寸长度
说明: C++标准没有明确基本数据类型的大小与存储格式, 这些基本类型包括: short, int, long, lo
long, float double等。这些基本数据类型在不同的编译器中,实现有所不同,如:
long类型在32位编译模式下为4字节长度,在64位编译模式下为8字节长度。
所以建议不要直接使用基本数据类型。推荐如下两种使用方式:
1、重定义基本数据类型
typedef int32_t int;
typedef int64_t long long;