19章 20章 C++中继承的用法 iostream库

来源:互联网 发布:淘宝网钱包 编辑:程序博客网 时间:2024/05/16 04:10

1、 Dynamic_cast操作符可以用来把一个类类型对象的指针转换成同一层次结构中的其他类的指针,同时也可以用它把一个类类型对象的左值转换成同一类层次结构中其他类的引用,注意dynamic_cast和其他的强制转换不同的是它是在运行时刻执行的。C++默认情况下不支持从基类指针到派生类指针的转换,但当我们必须使用派生类的某种特性,而该特性又没有出现在基类中且基类不易通过加入虚拟函数等方法修改时(如基类是类库),可以使用dynamic_cast来执行从基类指针到派生类指针的转换来使用派生类特性(因为基类指针只能访问该基类中被声明了的成员函数和数据成员),若转换失败,则dynamic结果为0,使用结果指针之前,必须通过测试dynamic_cast操作符结果来检验转换是否成功:if (derived *pd = dynamic_cast<derived*>(pc))。Dynamic_cast也可以把一个基类类型的左值转换成派生类类型的引用:derived &rd = dynamic_cast<derived &>(rc);如果转换失败,则会抛出一个std::bad_cast类型的异常,故必须包含头文件<typeinfo>。

 
2、 typeid(在头文件<typeinfo>中)在程序中可用于获取一个表达式的类型,如果表达式是一个含有虚拟成员函数的类类型,则获取的是其底层对象派生类的类型;若该类类型不含有虚拟函数,则获取的是该操作数原始类型,而不是底层对象的类型。Typeid操作符必须与表达式或类型名一起使用,实际上返回一个类型为 type_info的类对象。Type_info类的确切定义与编译器相关,其拷贝构造函数和拷贝赋值操作符私有,且无缺省构造函数,一般有公有的operator==(),operator!=()和成员函数name()返回一个type_info对象所表示类型名字的C风格字符串。
 
3、 抛出类类型的异常(throw expt(value))一般分为三步:

a)       throw表达式通过调用类类型expt的构造函数创建一个该类的临时对象(生命期到throw表达式结束)。

b) 在异常对象的存贮区中调用expt的拷贝构造函数创建第一步中临时对象的拷贝(生命期持续到所有异常被处理完毕,也即是最后一个catch字句退出时销毁)。

c)      在开始查找异常处理代码之前,第一步创建的临时对象被销毁。

注意:由于异常对象是通过拷贝throw表达式的值而创建的,故抛出来的异常总是在throw表达式中指定的确切类型。如:pushOnFull except(value);     stackExcp *pse = &except;   throw *pse;    //抛出的异常对象类型为stackExcp,即使pse实际指向一个pushOnFull类型对象。

 
4、 关于catch子句相关:

a)       catch 子句检查顺序是他们在try后出现的顺序,一旦编译器为一个异常找到了一个catch子句,就不会再进一步查找catch子句,故派生类的catch子句必须先出现,以确保只有在没有其他catch子句适合时,才会进入基类类型的catch子句(即catch子句列表中最特化的catch子句必须先出现)。

b)      Catch子句异常声明及调有方式与函数声明及调用相似(有传值和传址两种调用方式)。Throw和rethrow表达式抛出的异常对象是第二步在异常对象存贮区中创建的异常对象,通过引用传值可以在第一个处理的catch子句中作相应的处理再通过rethrow表达式重新抛出。

c)      若抛出的异常对象是派生类类型,且它被基类的catch子句处理,则catch子句一般不能使用派生类类型的特征,可通过给基类增加虚拟函数或使用dynamic_cast解决这个问题,但同时必须异常声明必须为传址方式(指针或引用),因为传值方式在函数调用栈中创建一个基类的临时对象,且以其派生类对象的一个子对象拷贝作为初始值。

 
5、 当一个异常被抛出时,为了寻找能处理该异常的catch子句,需要从抛出异常的函数内开始,向上通过嵌套的函数调用链,直到找到该异常的catch子句为止。在函数调用链中查找catch子句的过程称为栈展开。在栈展开期间,由于栈被展开,每次一个复合语句或语句块推出时,如果在退出块中有某一个局部对象是类类型的,则在复合语句或函数退出时,栈展开过程将自动调用该对象的析构函数。所以我们说c++异常处理过程反映的是被称为“资源获取是初始化,资源释放是析构”的程序设计技术的原因。
 
6、 异常规范相关:

a)       通过使用异常规范,函数声明可以指定在该函数中能直接或间接抛出的异常集合,异常规范跟在函数声明的const或volatile之后。

b)      同一个函数的所有声明和定义中的异常规范必须指定相同的类型,但派生类虚拟函数的异常规范只要求必须与基类对应虚拟函数的异常规范一样或者更严格(子集?)。

c)      被抛出的异常类型与异常规范中指定的类型之间不允许进行类型转换,但有一个例外:当异常规范指定一个类类型(或类类型指针时),该函数可以抛出“从该类公有派生的类类型(或类类型指针)”的异常对象。

 
7、 C++标准库的异常类层次结构(在头文件<stdexcept>中):

a)       根基类:exceptin,在头文件<exception>中定义,有缺省构造函数,拷贝构造函数,拷贝赋值操作符,及虚拟的析构函数和虚拟成员函数what()来返回一个C风格的字符串为抛出的异常提供某种文本描述,可以被其派生类改写以便更好的描述派生类的异常对象。且根基类exception的所有成员函数都不会抛出任何异常。

b)      二层基类logic_error(逻辑错误),runtime_error(运行时刻错误),bad_alloc(new操作符不能分配所要求的存贮区),bad_cast(dynamic_cast失败)。

c)      logic_error派生的invalid_argument,out_of_range,length_error,domain_error,runtime_error派生的range_error,overflow_error,underflow_error。

 
8、 c++的iostream库支持两种预定义的字符类型:char和wchar_t,后者与我们一般使用的前者不同仅仅在于每个类和类对象都加了前缀“w”,以便与相应的char型区分开。因此,wchar_t标准输入被命名为wcin,标准输出为wcout,以及标准错误wcerr。但两者所需要的头文件都是相同的。
 

9、 istream_iterator(#include <iterator>)支持在一个istream、或其派生类(如ifstream输入文件流)上的iterator操作。其一般声明形式为istream_iterator<Type> identifier(istream&);,这里type表示任意一个已定义了输入操作符的内置或者用户定义的类型,构造函数的实参可是一个istream类对象(如cin),或者任意公有派生的istream子类型(如ifstream)。应用在istream_iterator对象上的每个递增操作符,都用operator>>()读入输入流的下一个元素。为了通过istream_iterator和一个泛型算法读取输入流,我们需要提供一对iterator指示文件内部的开始和结束位置。用一个istream对象初始化的istream_iterator提供开始位置,为定义结束位置,我们使用专门的istream_iterator缺省构造函数。Ostream_iterator与istream_iterator类似,前者多了一种声明方式ostream_iterator<Type> identifier(ostream&, char* delimiter);这里delimiter表示一个C风格的字符串,它被输出到文件每个元素的后面作分隔符。

 

10、              表达式while (cin>>ival)从标准输入读入一个序列,直到cin为false时为止。有两种情况会使一个istream对象被计算为false:1、读到文件结束(在这种情况下,我们已经正确的读完文件中所有的值);2、遇到一个无效的值,比如若要求读入一个int类型的值,若输入中有小数点或者字符串文字,则istream对象被放置到一种错误的状态中,并且对于值的所有读入操作都将中止。且注意在缺省情况下,输入操作符丢弃任何中间空白(空格,制表符,换行符,走纸以及回车),若我们希望读入空白字符,第一种方法是使用istream的get()成员函数(与ostream的put()成员函数配合使用);第二种方法是使用noskipws操作符。

 

11、              iostream库的相关成员函数:

a)       get(char& ch)从输入流中提取一个字符,包括空白字符,并将它存储在ch中,返回被应用的istream对象。

b)      get()也从输入流读取一个字符,区别在于它返回该字符值(int而不是char)而不是被应用的istream对象。返回文件尾的标志通常用-1表示,为了测试其是否是文件尾,我们将其与iostream头文件中定义的常量EOF比较。故被指定用来存放get()返回值的变量,应该被声明为int类型,以便包含字符值和EOF。

c)      get(chart *sink, streamsize size, char delimiter=’/n’)中,sink代表一个字符数组,用来存放被读取到的字符,size代表可以从istream中读入的字符的最大数目,delimiter表示如果遇到它就结束读取字符的动作。注意delimiter字符本身不会被读入,而是留在istream中,作为istream的下一个字符,故在执行第二个get()之前,一定要使用istream成员函数ignore()来去掉delimiter。其返回值是被调用的istream对象。

d)      ignore(streamsize length=1, int delim=traits::eof)从istream中读入并丢弃length个字符,或者遇到delimiter之前包含delimiter在内的所有字符,或者知道文件结尾。它返回当前被应用的istream对象。

e)       gcount()返回实际被读入的字符个数,返回int。

f)       getline(char *sink, streamsize size, char delimiter=’/n’)与对应的get(…)类似,不同之处仅仅在于它丢弃delimiter而不是将其留作istream的下一个字符,其也返回被调用的istream对象。

g)      read(char* addr, streamsize size)从输入流中提取size个连续的字节,并将其放在地址从addr开始的内存中,返回当前被调用的istream类对象。

h)      putback(char c)将字符放回iostream。

i)        unget()往回重置“下一个”istream项。

j)        peek()返回下一个字符(或EOF),但不要提取出来。

以上十个成员函数都是类istream的成员函数。

k)      put(char)将字符输出到输出流中,返回被调用的ostream类对象。

l)        write(const char *sink, streamsize length)输出length长度的字符数组(包括内含的空字符),返回当前被调用的ostream类对象。

以上两个成员函数是类ostream的成员函数。

m)    标准库还给出了非成员的getline()函数:getline(istream *is, string str, char delimiter)。读入最大数目为str::max_size-1个字符。如果输入序列超出了这个限制,则读操作失败,并且istream对象被设置为错误状态。否则,当读到delimiter(它被从istream中丢弃,但没有被插入到string中)或遇到文件结束符时,输入字符串结束。

 

12、类的重载输出(输入)操作符的原型一般为ostream& operator<<(ostream&, const class_type&);(istream& operator>>(istream&, class_type&)),因为其第一个实参类型不是该类(class_type)的类对象,故其必须定义为类的非成员函数,且若其要访问类的私有数据成员,还要声明为该类的友元。

 
13、文件输入与输出相关:

n)      ofstream outfile(“D://cpp//copy.out”, ios_base::out);传递给ofstream构造函数的实参分别指定了要打开的文件名和打开模式。第一个实参类型的c风格的字符串,故若是string对象还必须使用c_str()将其转换为c风格字符串。Ofstream的打开模式有输出模式(ios_base::out)和附加模式(ios_base::app)两种,缺省情况下为输出模式。两种模式下,若文件不存在,都将创建一个新的文件,且若是输出模式打开已经存在的文件,则所有存在该文件的数据都将被丢弃。

o)      在试图读写文件之前,一定要先判断其是否成功打开。

p)      在定义ofstream,ifstream类对象时,也可以不指定文件,以后可以通过成员函数open()显式的把一个文件连接到一个类对象上。还可以通过成员函数close()断开一个文件与程序的连接。

q)      fstream类对象还可以打开一个同时被用于输入和输出的文件。Fstream io(“word.out”, ios_base::in|ios_base::app);,通过其成员函数seekg()(为了获取get字符而定位,用于ifstream类对象)和seekp()(为了放置put字符而定位,用于ofstream对象)我们可以对fstream类对象的光标重新定位。各有绝对地址和相对地址两种定位方法:seekg(pos_type current_position); //绝对地址,将光标设置到文件中固定的位置上(0是文件的开始)。 Seekg(off_type offset_position, ios_base::seekdir dir); //相对地址,从当前位置向某个方向进行偏移,position为正表示向前移动,为负则表示向后移动。dir可以被设置为ios_base::beg(cur,end)这三个选项之一,表示偏移值开始计算的位置。Tellg()和tellp()返回光标的当前位置。最后要注意,即使是文件被同时应用与输入和输出,其光标也只有一个,而不是有输入光标和输出光标两个。

 
14、只有在正常状态下,输入流才执行读操作,判断流对象是否处于正常状态:if (!cin),每个流对象都维护了一组条件标志,通过这些条件标志,我们可以监视流的当前状态,可以通过一下四个成员函数获取:eof()(如果一个流遇到文件结束符,则返回true),bad()(如果试图做一个无效的操作,比如seeking重定位操作超出了文件尾,返回true,这表明该流由于某种未定义的方式而破坏了),fail()(如果操作不成功,比如打开一个文件流对象失败或遇到一种无效的输入格式,则返回true),good()(如果其他条件都不为true,则返回true)。此外,还可以显式的修改流对象的条件状态,一是使用clear(Ios_base::iostate)成员函数,可以把条件状态复位到一个显式的值,缺省置为正常状态。二是使用setstate(Ios_base::iostate)成员函数,不复位条件状态,而是在对象的现有状态的基础上在增加一个条件状态。四个可用的条件状态值为:ios_base::badbit,ios_base::eofbit, ios_base::failbit,ios_base::goodbit。最后,rdstate()成员函数返回iostream类对象的状态。Ios_base::iostate state = cin.rdstate();
 

15、iostream库支持在string对象上的内存操作(#include <sstream>),ostringstream类向一个string插入字符, istringstream类从一个string对象读取字符, stringstream类可以支持读和写两种操作。其成员函数str()返回与stringstream类对象相关联的string对象。Ostringstream对象也可以用来支持复合string的自动格式化,即由多种数据类型构成的字符串。例如,输出操作符自动的将类型转换成相应的字符串表示,而不用担心所需的存储区大小。Istringstream由一个string对象构造而来,它可以读取该string对象,它的一种用法是将数值字符串转换成算术值。注意:只用<sstream>没有包含<iostream>。

 
16、每个iostream库对象都维护一个格式状态,控制格式化操作的细节,C++为程序员提供了一组预定义的操作符来修改对象的格式状态。应用操作符之后,不只是改变了后面输出值的表示形式,而且还修改了ostream的内部格式状态。但操作符带有一个实参时,就必须#include <iomanip>。
 
 
原创粉丝点击