今天主要是学习More Effective C++
1) 指针和引用的使用
指针:在对象为空时;不同的时刻指向不同的对象时
引用:总指向一个对象,并且一旦指向这个对象就不再改变时; 当时重载某个操作符时需要使用引用;
还有一个就是当对象为继承类,而参数为基类时,需要使用引用,防止其指向基类,而不是继承类对象
2) 使用C++风格的类型转换
static_cast< type >( expression ) 基本数值类型的转换
const_cast< >( ) 转换const,volatileness
dynamic_cast< >( ) 将指向基类的转换指向继承类
reinterpret_cast< >( ) 几乎是实现时定义,普通的用途是在函数指针类型间转换。
函数指针时: 例如 int something()
typedef void (*FuncPtr)()
FuncPtr p1 = reinterpret_cast<FuncPtr>(&something)
3) 在C++中一般希望数组中的对象都是一样的,因为他会根据大小来移位找到下一个对象,和其他脚本语言不一样。
尽量保证数组内的类型一样,且大小也一样。
4) 喜欢这段代码
class A
{
A(int i);
}
// create the memory
void * rawMem = operate new[](10 * sizeof(A));
A * aa = static_cast<A*>(rawMem);
for( int i = 1; i < 10; ++i) {
new (&rawMem[i]) A(ID);
}
//destruction
for( int i = 9; i >=0 ; --i) {
aa[i].~A();
}
operate delete[](rawMem);
5) 操作符重载时一般定义成friend性质,为了使可以实现较好的隐形类型转换。
6) 前缀和后缀的区别:
Int& operate++(); // ++前缀
const Int operate++(int) // ++ 后缀
++i; // i.operate++()
i++; // i.operate++(0)
7) 最好不要重载内建类型&& || 等
不能重载的有: . * :: ?: new delete sizeof typeid等
8) C++异常问题:
try{
}
catch(Exception e){
}
finally{
}
C++使用异常的不是很多,只有在必须要使用异常时才使用。
有很多在构造函数中使用异常,防止构造时就出现问题。
而在析构函数里最好不要抛出异常,防止发生内存泄漏等。
如果有异常抛出,最终一般会使C++调用terminate函数,终止程序。
异常抛出的对象必须被复制,不管是值传递还是引用传递。对象被拷贝的是静态类型,不管他的动态类型是什么。
例子:
catch (Widget& w) // 捕获Widget异常
{
... // 处理异常
throw; // 重新抛出异常,让它
} // 继续传递
catch (Widget& w) // 捕获Widget异常
{
... // 处理异常
throw w; // 传递被捕获异常的
} // 拷贝
区别:
第一个是抛出原来的,没有拷贝
第二个是抛出一个复制对象,且类型为Widget
在函数调用中不允许转递一个临时对象到一个非const引用类型的参数里(参见条款19),但是在异常中却被允许。
异常:推荐使用引用传递的方式
9) 异常规格:
当函数什么都没声明时表示可以抛出任何异常
如: extern void f1();
如果是只能抛出int类型的异常:
如: extern void f1() throw(int);
当不抛出任何异常的时候可以如下使用:
如: extern void f1() throw();
异常时需要时间代价的
10)代码效率问题
牢记: 80-20准则
11)考虑使用lazy evaluation,使用时复制方式
12) lazy calculate方式与over-eager calculate方式
13)通过重载避免隐式类型转换
推荐使用+= -= 而不是使用 + -
14)虚拟函数的使用
一般使用virtual table -> vtbl
vitual table poinsters -> bptr
虚函数一般不要声明为inline函数,因为它是动态绑定的,和静态绑定inline方式不一样。
15)虚拟构造函数和非成员函数等
总结:
1) 学会经常使用typedef,尤其是在类里,可以很好进行改进
2) strlen(NULL) 动作不确定, delete NULL; 没问题,可以
3) 语言内置关键字: sizeof new
还没有全部完成,后续继续写