赞
踩
以下为本人大一时阅读《C++ Primer Plus》中关于抛出异常章节所做的笔记
目录
访问函数(access fnction)和工具函数(utility function):
与结构体类似,对象的名称或者对象的引用可以和原点成员选择符(.)一起使用,而对象的指针则需要和箭头成员选择运算符(->)一起使用
判定函数(predicate function):用于测试条件是真还是假
工具函数(也称为助手函数):类的private成员函数,目的是支持类的public成员函数的操作,并非为类的客户使用而准备的
析构函数(destructor):在类的对象撤销之前,用于完成对该对象的“扫尾工作”。
防止一个头文件在一个程序中被多次包含:
- #ifndef TIME_H
- #define TIME_H
- ...
- #endif
ifndef:if no define(如果没有定义)
如果之前没有在文件中包含此头文件,那么TIME_H这个名字将被#define指令定义,并且包含该头文件的语句;
如果之前已包含此头文件,那么将不再包含该头文件
- try
- {
- ...
- }
- catch( 指定的错误类型 &e)
- {
- cerr<<"Exception: "<<e.what()<<endl;
- //(catch语句块内部也可以写其它的指令)
- }
注意:代码中指定类型的异常为其它头文件中的能指定错误的类型,例如在头文件<stdexcept>中的out_of_range、invalid_argument等,后面的 &e 是声明一个接收引用的异常形参,用来实现与捕捉到的异常对象的交互,e.what()是通过调用它的what成员函数打印异常的错误信息。catch语句块可以处理指定类型的异常。
当执行到以上步骤时,运行try中的语句,若存在异常,则运行catch中的语句(一般是用cerr输出关于错误的信息),然后再接着运行catch之后的程序;若不存在异常,直接跳过catch语句。一个try可以有多个catch块来处理不同的异常。
注意:在try语句块中声明的任何变量在catch语句块中都超出了它们的作用域,也就是说在catch语句块中都不可访问。
黏性设置与非黏性设置:
类定义体内的成员函数被隐式地声明为inline:
具有默认实参的构造函数:
注意:每个类最多只有一个默认构造函数(但可以有多个构造函数)
与一般函数一样,构造函数也可以有默认实参:
Time类:
- public:
- explicit Time(int=0,int=0,int=0);
Time类的成员函数定义:
- Time::Time(int hour,int minute,int second)
- {
- cin>>hour>>minute>>second;
- }
初始化3个Time对象:
- Time t1;
- Time t2(2);
- Time t3(12,25,42);
在C++11中可以使用列表初始器调用构造函数:
- Time t1;
- Time t2{2};
- Time t3{12,25,42};
或者写成
- Time t1;
- Time t2={2};
- Time t3={12,25,42};
上述三种初始化都实现了:t1使用了3个默认实参,t2指定了一个实参(按形参的顺序传递,之传入一个实参时是传给了hour),t3指定了三个实参
C++11:重载的构造函数和委托构造函数:
类的成员函数可以直接访问类的private数据,但一般都调用设置函数(如setTime)和获取函数(如getTime)来修改和访问类的private数据,这样做的好处是当需要修改设置和获取数据的方式时,只需修改设置函数和获取函数的内容,而不需要对所有涉及到操作和获取private数据的内容都进行修改。
命名:在类名之前添加(~)
当对象撤销时,类的析构函数会隐式地调用。
析构函数本身并不释放对象占用的内存空间,它只是在系统收回对象的内存空间之前执行扫尾工作,这样内存可以重新用于保存新的对象。
如果没有显式地提供析构函数,编译器会隐式生成一个“空的”析构函数
exit函数迫使程序立即结束,不执行自动对象的析构函数。当程序检测到输入中有错误,或者程序要处理的文件不能打开时,常常使用这个函数来终止程序。
abort函数的执行情况与exit函数类似,但是迫使程序立即终止,不允许调用任何对象的析构函数
总结:abort函数立即终止程序,exit函数终止程序前还进行一些清理工作
对象的存储类别对调用析构函数的顺序的影响:
全局作用域内对象:在文件内任何其他函数(包括main函数)开始执行之前调用构造函数、在main函数执行结束时调用析构函数
局部对象:当程序的执行每次进入或者离开自动对象的作用域时,自动对象的构造函数或者析构函数会被调用。(若程序的终止是由调用exit函数或者abort函数完成的,那么自动对象的析构函数将不被调用)
static局部对象:构造函数只被调用一次,即在程序第一次执行到该对象的定义处时,而相应的析构函数的调用发生在main函数结束或者程序调用exit函数时。全局或static对象的撤销顺序与它们建立的顺序正好相反。如果用abort函数的调用终止程序,那么static对象的析构函数将不被调用。
=是赋值运算符,它的作用是将一个表达式的值赋给一个左值。一个表达式或者是一个左值,或者是一个右值。所谓左值是指一个能用于赋值运算左边的表达式。左值必须能够被修改,不能是常量。这里是用变量作左值,指针和引用也可以作左值。
如果函数返回的是一个const引用,那么这个引用不能用作可修改的左值。
返回private数据成员的引用或指针:
对象的引用就是该对象名称的别名,可以在赋值语句的左边使用。
在类的定义中:
- public:
- int &badSetHour(int);
- private:
- int hour;
在类的成员函数定义中:
- int &Time::badSetHour(int hh)
- {
- hour=hh;
- return hour;
- }
- int Time::getHour()
- {
- return hour;
- }
在main函数中:
- int main()
- {
- Time t;
- int &hourRef=t.badSetHour(20);
- cout<<t.getHour()<<endl;
- hourRef=30;
- cout<<t.getHour()<<endl;
- t.badSetHour(12)=74;
- cout<<t.getHour()<<endl;
- }
输出:
20
30
74
总结:通过引用hourRef来修改private中的数据,其中hourRef在声明的同时已用调用t.badSetHour(20)返回的引用来进行初始化。在这个过程中展示了hourRef如何破坏了类的封装性——main函数中的语句不应该有访问该类的private数据的权利。最后使用badSetHour函数调用本身作为左值,将74赋给该函数返回的引用。这个过程中,hour的值先是被赋值为传入badSetHour函数的参数12,然后被返回为引用,再被修改为74
默认的逐个成员赋值:
赋值运算符(=)可以将一个对象赋给另一个类型相同的对象,默认情况下是将=号右边对象的每个数据成员逐个赋值给左边对象同一个数据成员。对于每个类,编译器都提供了一个默认的复制构造函数,可以将原始对象的每个成员复制到新对象的相应成员中。对象可以作为函数的实参进行传递,也可以由函数返回。这种传递和返回默认情况下是以按值传递的方式执行的。
修改const对象的任何企图在编译时就会被发现,而不是等到执行期才导致错误
以下调用是允许的:
1.对非const对象调用非const成员函数
2.对非const对象调用const成员函数
3.对const对象调用const成员函数
注意:对const对象调用非const成员函数是不想允许的
以下这句话差不多可以跟函数的声明顺序一样理解
创建顺序、撤销顺序:
由内而外创建、由外而内撤销(例如,Date成员对象作为Employee成员对象中的成员,则Date成员对象先创建,Employee成员对象后创建,同时Date成员对象在Employee对象撤销后再撤销)
类的friend函数在类的作用域之外定义,却具有访问类的非public(以及public)成员的权限。单独的函数、整个类或其他类的成员函数都可以被声明为另一个类的友元。
friend的声明:
使用friend函数修改类的private数据;
友元声明可以出现在类的任何地方。按照惯例,友元声明首先出现在类的定义中。
- class Count
- {
- friend void setX(Count &,int); //***
- public:
- Count():x(0){}
- private:
- int x;
- };
-
- void setX(Count &c,int val)
- {
- c.x=val;
- }
- int main()
- {
- Count counter;
- setX(counter,1);
- }
上面的程序中使用了友元函数setX将类成员对象counter中的private成员x进行了修改。如果将标记了***行中的友元声明去掉,就会出现错误信息(一般类之外的函数不能对类成员对象中的private成员进行修改)
(实验课后的总结:友元函数的编写要注意编写程序的顺序,详细可以参考C++文件中实验课的2.1.6和2.1.7以及https://blog.csdn.net/jw903/article/details/38864769)
每个对象都可以使用this指针来访问自己的地址
对象的 this指针不是指针本身的一部分,占用的内存大小不会反应在对对象进行sizeof运算得到的结果中。
this指针作为一个隐式的参数(被编译器)传递给对象的每个非static成员函数
使用this指针来避免名字冲突:
一个常用的this指针的explicit应用是用来避免类数据成员和成员函数参数之间的名字冲突。
在下面的例子中,设类Time有数据成员hour:
- void Time::setHour(int hour)
- {
- this->hour=hour;
- }
上面的程序将传进setHour函数的hour参数赋值给数据成员hour
this指针的类型:
隐式和显式使用this指针来访问对象的数据成员:
- void Test::print() const
- {
- cout<<x<<endl; // 1
- cout<<this->x<<endl; // 2
- cout<<(*this).x<<endl; // 3
- }
上述输出的都是Test成员对象中的数据成员x的值,第一个隐式地使用this指针,仅仅指明该数据成员的名称,第二个和第三个使用不同的表示法通过this指针访问x。第三个请注意:*this必须用括号括起来,后面再跟随圆点成员选择运算符( . ),这样的原因是圆点运算符具有比*运算符更高的优先级(也即是*this.x的含义与(*this).x的含义不同)
使用this指针实现串联的函数调用:
串联的函数调用也就是多个函数在同一条语句中被调用
下面给个例子:
Time类的声明中:
- public:
- Time &setTime(int,int,int);
- Time &setHour(int);
Time类成员函数定义:
- Time &Time::setTime(int h,int m,int s)
- {
- ...
- return *this;
- }
- Time &Time::setHour(int h)
- {
- ...
- return *this;
- }
main函数中调用串联的成员函数:
- int main()
- {
- Time t;
- t.setHour(18).setMinute(30).setSecond(22);
- }
串联的成员函数调用过程解读:
t.setHour(18).setMinute(30).setSecond(22);
先求t.setHour(18)的值,返回对对象t的引用,作为此函数调用的值。
接下来转化为:
t.setMinute(30).setSecond(22);
再接着转化为:
t.setSecond(22);
对于类的每个对象来说一般都各自拥有类所有数据成员的一份副本。但是static数据成员仅有变量的一份副本供类的所有对象共享。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。