一、将C++视为一个语言联邦
C++ ≈ {C, C with class, Template C++, STL}
,对于内置类型而言,Cpp采用以值传递的方式更高效,而对于用户自定义类型而言,一般采用以常引用传递的方式更好(这其中的成因与底层指令相关,所以学一学汇编是很重要的),在使用CPP哪个部分时,遵循那个部分。
二、尽量不要使用C中的define语句
尽量不要使用define
,尽管define
很高效,但他只是忠实地替换了原始代码,会造成很多问题比如:
定义
#define ABC 114514
时,由于编译器在预处理阶段移走了ABC
而用114514替代,之前ABC的标记已经没有了,若是出了问题,打印的错误信息很可能是error: 114514……
,而不是error ABC...
,在带项目中难以定位,建议用const int ABC = 114514
替代,出错也好debug考虑使用宏:
1
2
3
4
int a = 5, b = 0;
max(++a, b); //a会自增两次
max(++a, b + 10); //a自增一次这显然非常扯淡,一般而言,使用inline函数模板代替宏,更安全,更省心
tips: 内联函数与宏的区别
1、内联函数在编译时展开,而宏在预编译时展开
2、在编译的时候,内联函数直接被嵌入到目标代码中去,而宏只是一个简单的文本替换。
3、内联函数可以进行诸如类型安全检查、语句是否正确等编译功能,宏不具有这样的功能。
4、宏不是函数,而inline是函数
5、宏在定义时要小心处理宏参数,一般用括号括起来,否则容易出现二义性。而内联函数不会出现二义性。
6、inline可以不展开,宏一定要展开。因为inline指示对编译器来说,只是一个建议,编译器可以选择忽略该建议,不对该函数进行展开。
7、宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器符号表中的简单替换,因此它不能进行参数有效性的检测,也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型,这样,它的使用就存在着一系列的隐患和局限性。
想在编译期使用宏定义类似的功能,可使用
enum hack
大法,enum的行为很像加了限制区间的宏定义
三、尽可能多地使用const:
区别const int *
和int * const
,前者修饰的是指向的东西,后者修饰的是指针
对于STL迭代器,其规则与主语言又有所不同:
1 | const vector<int>::iterator iter; //相当于int * const,迭代器指向不能改变 |
对于运算符重载,最好将运算数声明为const-reference
,并在重载时,考虑与基本类型运算符行为保持一致。
const对象只能调用const成员函数,这是符合const语义(不修改)的,同理,const成员函数内部只能访问成员变量,但无法修改,也无法访问普通成员函数(普通成员函数可能修改成员变量)
将一些函数,变量加const可帮助编译器检查错误用法
const和non-const版本的函数除了返回以外无差别时,可使用强转令non-const调用const
1
2
3
4
5
6
7
8
9
10
11const char& operator[](std::size_t position) const{
........
}
char& operator[](std::size_t position) {
return
const_cast<char &>(
static_cast<const A&>(*this)
[position]
);
}
四、确定对象使用前被初始化:
为确保对象的行为如你预计般地可靠,必须确保每个对象使用前被初始化
对于成员对象,通常采用初始化列表的形式构造:
1
2
3
4
5
6
7
8
9
10
11
12class People
class Society{
private:
People p;
int nums;
const string rule;
public:
Society(const People& tp, const string& s, int n):
p(tp),
rule(s)
{nums = n};
}通常,写为初始化列表的成员对象直接调用自己的构造函数进行构造,而采若用赋值的方式,其行为往往是使用default构造函数构造成员对象,再使用重载的”=”进行赋值。
类型为引用和常量的成员变量必须使用初始化列表,不能采用赋值的形式
对于一些初始化和赋值表现一样好的成员,可考虑写一个init函数,供多个不同的构造函数使用
对于non-local static对象,即多个文件(作用域,对象……)共享的静态对象,由于我们无法确定初始化顺序,而在一个对象未被初始化前调用它是很危险的,所以我们一般采用单例模式
1
2
3
4
5
6
7
8
9class test{
private:
test(){}
public:
test& get_test(){
static test t;
return t;
}
}