放在这里也许没有人会看到,但是通过这几天做的笔记,我还是发现了这有一个好处,可以驱使我进一步的学习下去。我希望我能够坚持到把这本将近800页的书看完,呵呵。
3.6 const成员函数
1.实现:type func() const;
*const成员函数必须在函数声明和函数定义处都加上const符号标志
%通过声明为const成员函数首先可以防止以外的更改类的状态,这样也就可以让类的使用者更放心大胆的使用你所编写的类,因为它的const是在编译器级别实现的。
2.特殊情况下可以使用mutable限定符声明后可以在const成员函数内部对对象进行修改。
3.const成员函数在编译器内部的实现是通过把this指针声明为const而实现的。
3.9 c++中类可以包含的内容:
1.原始类型数据成员(int,char etc);
2.另一个类的对象;
3.类(相同或另一类)的指针和引用;
4.指向原始类型的指针或者引用;
5.静态数据成员;
6.成员函数(静态或非静态的);
7.另一个类的成员函数的指针;
8.另一个类的声明(嵌套类)。
3.10 类接口的设计
1.要合理的设计成员的可见性;
2.为了方便别人的使用,成员函数的命名以及参数的名字都要力争达到名--意一致;
3.要有简单清晰的说明文档;
4.正确的选择参数的选择方式,比如不修改的情况下要多用const声明,大的参数要使用引用或者指针等等;
5.函数的返回值要真正起到作用;
6.必须对你设计的类所产生的对象的内存安全负责。
四oop中的初始化和无用单元的回收
4.1初始化
1.在定义局部变量时最好一起初始化,而不要再通过赋值来完成初始化;
2.要尽量使用构造函数来初始化对象的所有内部数据成员。
%可以使用合适的特定的值来初始化数据成员,而且一旦在成员函数的调用中出现这种值,所有使用成员数据的函数要能检测到并且做出决定(检测无现实意义但是正确的数据成员),比如一个表示人的类,其年龄一开始被初始化为0,虽然0是一个合法的整数,但是在这里没有意义,这样一方面可以保证程序的健壮,另一方面也可以检测到该对象是没有经过正确的赋值的。
3.给const成员初始化的方式
class obja{
obja(int arg);
~obja();
private:
int c;
const int d;
}
初始化方式:obja:obja(int x):d(x){......}
初始化语法:构造函数括号之后的:符号指出初始化序列的开始,:到{之间的操作既初始化。
4.对包含另一个类的对象的初始化
同样的初始化语法:classa:classa(int a):classb(int b,char c){......}
4.2无用单元收集问题
1.悬挂引用:
当指针所指的内存资源已经被删除时,但仍被误作为合法的指针使用。
%char *q,*p;
p=new char[255];
q=p;
delete []p;
p=0;
%如果再对指针q指向的内存进行操作就会产生悬挂引用,比如*q='asdasd';
2.c++不会主动为你收集无用内存,你必须利用c++语言自己处理。
%回收资源一般可以放在析构函数中实现。
4.4对象标识
1.一个对象可以有不同的名称或者有不止一个指针指向它,但是其标识只能有一个,它就是内存中的地址。
4.5对象的复制
在对象中还包含其他资源的时候,一般编译器自动实现的复制构造函数往往不会符合要求。
%对于对象中保存的资源指针,默认的复制构造函数是把它当作一个整数来直接进行复制,这样当复制操作完成后两个对象的指针会指向同一内存地址,这是删除任何一个对象就会造成另一个对象在访问该内存时出现指针悬挂引用。
4.6对象赋值的语义
对象之间的相互赋值总是有程序员明确调用的操作。例如 a=b;
4.7对象相等的语义
对象相等:两个对象的状态一样;
对象等价:两个名称或两个指针实际上都是指的内存中相同地址的一个对象;
%对象之间的比较可以通过重载比较运算符<,>,<=,>=,==,!=来实现。
4.8对象副本的控制
限制对象副本的个数或者说在特定的情况下只允许有该类的一个实例。
用途:1.信号量控制
2.判断权限后才可以进行的对象的复制等等。
4.10“写时复制”的概念
对于占用资源较多的对象,在对象复制时可以采取先让两个对象之间共享资源(指针指向同一内存地址),直到某一对象需要对共享的资源进行修改的时候才真正在内存中产生其共享资源的两个副本,然后对需要修改的对象的资源进行修改。这样就不会破坏另一个对象的状态。
但是对象必须要可以检测到这种改变而且要完善的处理。
对于“写时复制”有三个基本要求:
1.必须可以共享资源而不会导致额外的成本(cpu,内存),否则失去其意义;
2.必须能明确区分和控制可能修改资源的所有途径;
3.必须能够跟踪所有环境中共享资源的对象的数目。
小结:
1.对于使用默认构造函数后马上进行赋值的操作要尽量选择复制构造函数。
2.类的实现者要负责处理关于内存回收和防止指针悬挂的产生。
3.一般情况下要自己重载赋值运算符以及自己实现复制构造函数,编译器产生的只是简单的对对象数据成
员的复制,而不会包含对象多拥有的任何资源。
4.c++中可以自己重载一些运算符而简化编程,防止出现不可预料的结果。
5.在合适的情况下多使用const限定符。
6.正确的初始化既可以防止程序的崩溃又可以让对象的状态得到确认。