构造函数初始值列表
如果类的成员有const, 引用,没有提供默认构造函数的类类型。那么我们必须通过构造函数为这些成员赋初始值。
class Testcase
{
public:
Testcase(int ii): i(ii), ci(ii), di(ii){};
private:
int i;
const int ci;
int &di;
}
一般来说,建议直接使用构造函数初始化成员。一方面是初始化和赋值关乎底层效率问题,另外一方面是一些数据成员必须被初始化。
虚函数
基类希望派生类进行覆盖的函数通常定义为虚函数,当我们使用指针或者引用调用虚函数时,这个调用将执行动态绑定,根据指针和引用指向的对象类型来决定调用基类版本的还是派生类版本的函数。
静态类型和动态类型
基类的指针和引用的静态类型可能与动态类型不一致,因为可能他指向基类的的对象,也可能指向派生类的对象。当使用一个派生类对象为一个基类对象初始化或者赋值时,只有派生类对象中的基类部分会被拷贝,赋值,移动,它的派生部分会被忽略掉。
new&&delete
new运算符会分配要求数量的对象并且返回一个指向第一个对象的指针.
int* p = new int[10];
typedef int arrt[10];
int *p = new arrt;
delete一个指针后,指针值就变成无效了,但是许多机器上的指针仍然保存在已经释放了的动态内存的地址,这时指针就变成了空悬指针。
int *p = new int[10];
cout<<p[9]<<"--"<<p<<endl; //输出数组中最后一个元素,和数组的首元素的地址
delete [] p; //释放动态内存
cout <<p[9]<< " --"<<p<<endl; //实际上p变成了空悬指针,此时两次输出p的地址仍然相同,仍然可以访问被释放了的地址,很奇怪
抽象基类
不能直接创建一个抽象基类的对象; 派生类的构造函数只初始化它的直接基类;
基类中的析构函数最好定义为虚析构函数,这样派生类中的析构函数就会继承基类的析构函数,当使用基类的指针绑定了一个派生类对象时,执行delete基类指针时,能够确保运行派生类和基类的析构函数。
读文件流fstream
ifstream fin;
fin.open(文件名,ios::in|ios::binary);
fin.read(unsigned char * buff, int num); //从文件中读取num个字符到缓存中
fin.eof(); //用来检测是不是到了文件的末尾
fin.seekg(int offset, ios::beg) //从文件开头往后移offset,ios::cur 当前位置, ios::end 文件的末尾
fin.tellg(); //返回文件当前读位置的字节编码
虚析构函数
继承关系中处于根节点位置的类通常会定义一个虚析构函数。