1, C++.federation.png
2, const + enum
kill #define
functions: inline
kill #define
3 use const
whenever possible
const char *p = "hello"
const data, non-const pointer
char * const p = "hello"
non-const data, const pointer
4, default member function
class Empty
{
public:
Empty(){} //构造
Empty(const Empty& rhs){} //拷贝构造
Empty(const Empty&& rval){} //移动构造
Empty& operator=(const Empty& rhs){} //赋值
Empty& operator=(const Empty&& rval){} //移动赋值
~Empty(){}
};
5 c++ 不允许reference指向其他对象
int a = 1,b=2
int &ra = a,&rb = b;
ra = b; //此处是assignment, 此时已经修改了a的值,但是ra依旧是a的reference
7 不想或不允许使用default member function时
- 声明为private, 不去实现或定义
- 使用Uncopyable这样的base class
8 不要让exceptions逃出destructor
程序出现exceptions时,系统会自动调用相应的destructor,此时如果有多个object的destructor被调用,
意味着有多个exceptions同时出现,然后系统就蒙了
9 对于多态的base class,最好将其destructor声明为virtual
why not constructor be virtual?
1, 虚函数实行run-time binding, 在constructor之前,无法确定the type of the object, so, 无法调用虚函数
10 not call "virtual function" in "constructor" and "destructor"
//.h
class Base
{
Base()
{
vfun();
}
virtual vfun();
};
class Derive:public Base
{
Derive()
{
vfun();
}
virtual vfun();
}
//.cpp
Derive d; //此时,base class的constructor先于derive class的constructor,当base class完成构造时,由于derive尚未构造,此时会调用base class的虚函数,违背了虚函数与实际对象一致的规则
11 operator= 返回reference to *this
假设返回对象本身,a=b=c,首先执行b=c,返回一个临时的对象temp(需要用到构造函数),然后再执行a=temp,增加了拷贝代价
当然该协议也适用于operator +=, -=,*=, /=
12 operator= 处理自我赋值
1, 添加 identity test(不能保证异常处理)
2,
exception safe.JPG
13 如果自己写copy constructor,确保copy所有的local variable and all the variable in the base class, 否则编译器不会再提醒你
another advice: 不要在copy constructor 与copy assignment之间互相调用,因为语义不符
前者是构造对象,后者是已经完成对象初始/构造 化的重新assignment
13 RAII(resource acquisition is initialization), 使用对象管理资源,主要是shared_ptr<>
shared_ptr<int> ptr = new int;
attention, 对于shared_ptr <int> p(new int[10]), 析构时也无法完成,因为调用的是delete, not delete[], to solve this, 使用vector/string 代替array.
14 copy RAII对象时记得copy他对应的resource
15 RAII对象中需要对原始资源进行访问时,可以显示调用(更加安全),隐士调用(方便但可能不安全)
17 独立语句完成RAII对象
int fun1() //a function
fun((shared_ptr<T>) new T, fun1()) //此时编译器会对同一行的语句进行优化,意味着2B编译器会出现以下顺序:
1 new T
2 fun1()
3 shared_ptr<T> = p;// p = new T
如果在2中throw exception, 意味着new了一块东西,却没办法释放
20 pass-by-reference-to-const 代替pass-by-value
1, 更高的效率 //注意一般为const,不然很容易修改对应值
2,避免slicing problem,其实就是参数为base class, 传进来的却是derived class
3, 对于短小精悍的内置类型和函数对象还是pass-by-value
24 所有参数需要类型转换时,采用non-member
class Rational
{
public:
Rational(int a=0,int b=0);
const Rational operator*(const Rational& rhs)
{...}
int a, b;
};
Rational ration(1,2);
Rational m = ration * 2; //correct equal: m = ration.operator*(2);
Rational m1 = 2 * ration; //wrong! equal: m1 = 2.operator*(ration)
why? 当变量位于参数列表中时才会发生隐士转换。第一个,调用operatpr*后需参数为Rational, 发生Rational tem = 2;第二个,2不是一个class,无法调用operator,即2无法置身于一个参数列表中
26 尽可能延后变量出现的时间,尽可能出现即初始化(效率)
27 在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全; const_cast 唯一可以去掉const的修饰
28 避免返回handles(包括reference,pointer,iterator)指向对象内部,因为对象可能会析构,只留下一个dangling handle.
异常安全的函数特点:
1, leak no resource
2, don't allow data structure to be corrupted
32 public 继承,表示“is_a”, 适用于base class的每一种操作也适用与derived class ;
33 derived class 会遮掩 base class的名称,而在public继承下希望去除遮掩,可以using 或 forward functions.
class Base
{
void f1();
void f1(int);
virtual void f2();
};
class Derived: public Base
{
void f1();
virtual void f2();
};
Derived d;
d.f1(); //correct, call derived f1();
d.f1(2); // no function in derived class;
34 public继承中,derived class 总是继承base class的所有接口
pure virtual : 只具体制定接口继承
virtual : 指定接口继承同时指定了缺省的实现
non-virtual : 指定接口继承以及强制性实现继承
37 不重新定义继承而来的缺省参数值
c++为了效率,对缺省参数静态绑定
38 is_a has_a is_implemented_in_terms_of
is_a : public inheritance, 所有适用于base class的操作都适用于derived class
has_a: in application domain, composition means "has_a", in implementation domain, composition means "is-implemented-in-terms-of".
42 申明template时,class 与typename 等价;但typename可以表示嵌套从属类型
template<class T>
void fun(T& C)
{
C::const_iterator ite; //此时编译器无法确定C::const_iterator是一个类型还是一个变量,统一认为不是一个类型,前面加上typename来表示其代表一个类型
}
网友评论