1、尽量以const,enum,inline替换#define
const double testconstdefine=1.2;//外部常量
class mainloop{
private:
static const int numstatic;//类内部常量
enum {
numTurns=5
};
int scores[numTurns];
};
const int mainloop::numstatic=5;
2、const的使用
const int* testa;//const在星号右边表示自身是常量,出现在星号左边表示所指物是常量 ,出现在星号两边,表示两者都是常量
const int* const testb;
std::vector<int> tesvec;
const std::vector<int>::iterator it=tesvec.begin();//it指针是常量,不可改 it++ 是错误 的
std::vector<int>::const_iterator itconst=tesvec.begin();//it指向 的东西是常量,不可以改,*itconst=10是错误 的
3、赋值与初始化的区别
mainloop::mainloop():stringa("tests")
{
stringa="tests";
}
初始化是默认会调用的,如果没有初始化,系统会调用stringa的默认构造函数进行初始化。而如果用赋值的话,系统默认做的事会白做,影响效率。
c++初始化类的顺序:先base class 后继承的class
4、编译器暗自为class创建default构造函数 ,copy构造函数 ,copy assignment构造函数
如果要驳回编译器的自动行为,可将该函数声明为private并且不予实现是,或者通过基类来杜绝
5、base classes 应该声明一个virtual 析构函数,如果 class带有任何virtual函数,它就应该拥有一个virtual析构函数
class的设计目的如果不是作为base class使用,或者不是为了具备多态性,就不应该声明为virtual 析构函数
6、在构造函数和析构函数中不要调用virtual函数,因为有可能会调用 不到真正想要的函数
7、operator=返回一个引用
8、四种转型
const_cast<T>(expression) 去掉const
dynamic_cast<T>(expression)安全向下转型 ,用来决定某对象是否归属继承体系中的某个类型
reinterpret_cast 低级转型
static_cast 强迫隐式转型
尽量避免使用dynamic_cast,影响效率
9、继承类的名称会遮盖基类的名称,如果想让被遮盖的名称再见天日,可使用using声明式
10、new、operator new、placement new
class MyClass {…};
MyClass * p=new MyClass;
这里的new实际上是执行如下3个过程:
1调用operator new分配内存;
2调用构造函数生成类对象;
3返回相应指针。
operator new 就像 operator+ 一样,是可以重载的placement new是operator new的一个重载版本,只是我们很少用到它。如果你想在已经分配的内存中创建一个对象,使用new是不行的。也就是说placement new允许你在一个已经分配好的内存中(栈或堆中)构造一个新的对象。原型中void*p实际上就是指向一个已经分配好的内存缓冲区的的首地址。我们知道使用new操作符分配内存需要在堆中查找足够大的剩余空间,这个操作速度是很慢的,而且有可能出现无法分配内存的异常(空间不够)。placement new就可以解决这个问题。我们构造对象都是在一个预先准备好了的内存缓冲区中进行,不需要查找内存,内存分配的时间是常数;而且不会出现在程序运行中途出现内存不足的异常。所以,placement new非常适合那些对时间要求比较高,长时间运行不希望被打断的应用程序。
使用方法如下:
1. 缓冲区提前分配
可以使用堆的空间,也可以使用栈的空间,所以分配方式有如下两种:
class MyClass {…};
char *buf=new char[N*sizeof(MyClass)+ sizeof(int) ] ; 或者char buf[N*sizeof(MyClass)+ sizeof(int) ];
2. 对象的构造
MyClass * pClass=new(buf) MyClass;
一旦这个对象使用完毕,你必须显式的调用类的析构函数进行销毁对象。但此时内存空间不会被释放,以便其他的对象的构造。
pClass->~MyClass();