C++学习笔记(2)

--------------------------------面向对象编程之继承---------------------------------------------------------


1、定义一个类的时候想重用一个已经有的类,就可以使用继承。
    class  NewClass : public  OldClass{
            //新增加的成员
    };
    新类会继承旧类的全部成员,成为新类中的成员。新类可以增加新的成员,实现对旧类的扩展。继承方式可以有public/private/protected三种,一般使用public方式。旧类成为“父类”或者“基类”,新类成为“子类”或者“派生类”。无论那种继承方式都是把父类的成员全部继承(复制)到子类中成为子类的成员,其中私有的成员在子类中不能直接访问,公开可以在子类中直接访问。特权是父类中可以用protected来作为成员的访问限制,这种成员称为保护成员。这种成员对外跟私有成员一样,但是在子类中允许直接访问。***尽量不应protected以免父子类之间有太强的耦合***。
    不同继承方式区别在于继承到子类中之后作为子类的成员对外的访问限制。private方式继承过来后所有成员都成为子类的私有成员,protected方式继承过来之后原来的私有成员还是私有的,原来保护的和公开的都成为子类的保护成员了;一般用public方式继承,继承过来的成员到子类中之后保持原有的访问限制不变。默认是private方式。
    继承主要作用是代码重用以及对多态提供支持。
    创建对象的顺序:构造函数首先调用父类的构造函数,然后按照定义顺序创建成员对象,执行构造函数的函数体。析构跟构造函数相反。构造函数默认调用父类构造函数时不传参数。如果需要传递参数,要在初始化列表中用父类类名来表示。***初始化列表各项排名不分先后,只是指明用什么初始化谁***
    子类定义的函数会隐藏来自父类的同名函数,即使参数表不同也不会构成重载。如果确实需要调用来自父类的那个函数,需要用“类名::”来指明。父子类之间不存在重载。
2、多重继承:一个类可以继承多个类,把所有父类的成员都全部继承过来,可以为每个父类指定一个继承方式。
    继承是一种“是一个”的关系,比如:老师是一个人。
    多个父类的构造函数按继承顺序调用,与初始化列表中的顺序无关。析构顺序相反。
3、虚继承:如果希望某一个类被继承到某一级子类中时有了多份要合并只保留一份,这个类在被继承时应该用virtual声明为虚继承,这个类就称为虚基类。
    虚继承(钻石继承)中虚基类的构造函数由最底下合并的那个子类的构造函数直接传递参数。
              虚基类
              /        \
          子类1   子类2
             \         /
                子类


------------------------------------------多态---------------------------------------------------------------
1、什么是多态:对各种对象发出同一种指令时,各个对象能根据自身的情况做出相应的响应。
    如果希望在调用函数时系统根据对象的真实类型去转调用相应的函数,需要把那个函数声明为virtual虚函数。子类中可以覆盖这个函数,也自动成为虚函数,覆盖(override)要求函数名和参数表都相同而且返回类型也要一致(比如父类中返回父类指针子类中可以返回子类指针)。
    虚函数表:编译器把这个类的全部虚函数的地址都保存在一张表中。每个这种类的对象里会藏一个指针指向这个虚函数表(在构造函数里做的),对象长度会增加4个字节。


    利用多态实现类型识别:
        dynamic_cast < 子类类型 & >(是父类类型的对象)把看起来是父类类型对象转换成子类类型对象,一般用这个结果来初始化一个子类类型的对象的引用或者当场使用。成功则一切顺利,失败则抛出异常终止程序。
        dynamic_cast < 子类 * >(是父类类型的对象地址)成功则结果为一个正常的子类地址,失败则结果为NULL。常常用这一种。
    dynamic_cast要求类有虚函数。
    typeid关键字实现类型识别:
        #include<typeinfo>
        typeid(类型或者数据)返回一个type_info & ,type_info里有一个成员name()表示类型的名字,type_info支持==和!=。依赖于编译器。如果累有虚函数,typeid也会利用多态进行类型识别。
------------------------复习:---------------------------------------------------------------------
    class  A{
        A(int  n){}
        A(double  d){}
        A(const  A&  x){}
    };   //拷贝构造函数
    A  a1(1);         A  a2(1.1);            A a3(a1);


    void  func(A  obj);
    func(1);//func ( A(1) );
    func(1.1);//func( A (1.1) );
    func(a1);//A  obj(a1); ==> A( A  x)==>A  x(a1)
--------------------------------------------------------------------------------------------------------
2、纯虚函数:没有必要或者不应该有函数体的虚函数,用“=0;”来取代函数体。有纯虚函数的类称为抽象类(缺少函数体),不允许直接用抽象类创建对象抽象类总是用来作为父类,由子类来实现(覆盖)那些纯虚函数,从而可以创建子类类型的对象,可以当成父类对象来引用,或者可以用父类指针指向子类对象。
    ***使用多态时必须通过父类指针或者引用来访问子类对象,而不能重建一个父类对象***
    多态也称为动态绑定、晚绑定、运行时绑定。统一接口,便于替换和维护。


3、通过父类指针动态释放子类对象时,默认调用父类的析构。如果希望使用多态调用对象所属的子类的析构函数,应该在父类中把析构函数也声明为虚函数。(可否为纯虚函数?构造可否为虚函数?)
4、string类:C++风格的字符串类,< string >
    构造函数:string(const  string &  s),string(const  char  *  s),string(int  n,char  c)。
    运算符:<<,>>,=,+,+=,[ ],at( int ),比较运算符<,<=,>=,>,==,!=
    长度:size( ),length( ),bool  empty( ),resize(newsize,fillc)
    转换成C风格:c_str( ),data( )不保证‘\0’,copy( char * to, int  字符数,int  start=0)复制从start位置开始的n个字符到to所指向的地方。
    字串:substr( int  start , int  n)返回从start开始的n个字符组成的一个字串string对象,原对象还保持不变。
    追加:append( int  n ,char  c)在末尾追加n个字符
    查找:find( char  c, int  start=0 )
               find( const  char  * s, int  start=0 )
               find( const  string &  s, int  start=0 )
               rfind( ... )参数同上,是从反方向查找,其中可以用string : : npos表示末尾
               find_first_of( 字符串 s,int  start=0 ),从start位置开始查找在字符串s中包含字符。find_first_of(“+-*/”)表示在原字符串中找第一个运算符。
               find_last_of( ... )
               find_first_not_of(...)
               find_last_not_of( ... )
               找到返回下标,没有找到返回string : : npos。
    删除:erase( int  start=0, int  n=string : : npos )
    替换:replace( int  start ,  int  n,  新字符串)
               replace( int start ,  int  n , int  n2 ,  char  c2)
            把从start位置开始的n个字符替换成新字符串或者n2个c2.
    插入:insert( int  pos, 新字符串)
              insert( int  pos, int  n, char  c)
    行输入:gets( buf )容易越界,fgets( buf ,siezof( buf ), stdin )保留了换行符在末尾,scanf( "%[^\n]" , buf )读到'\n'为止,也容易越界。
            string  s; getline( cin , s );


3、异常处理:
    什么是异常:不常发生,但无法避免。
    处理:
        返回错误码
        设置errno全局变量
        抛出异常
    捕获异常:
        用try{}把可能发生异常的代码包起来,紧跟其后用若干个(至少一个)catch(类型 e){}来捕获指定类型的异常并处理,处理之后程序从最后一个catch块后继续运行。
    抛出异常:throw  数据 ;


------------------------------------复习---------------------------------------------------------------------
1、多态(统一用父类引用或者指针调用虚函数),虚函数,虚表指针,动态类型识别(dynamic_cast < 子类 * > ( 父类 * ),typeid == >  type_info,#< typeid >,name( ),==,!=),纯虚函数=0;抽象类(不能直接用来创建对象,但可以引用或者指向已经有的子类对象),虚析构函数(用delete通过父类指针释放子类对象时用)。string类,异常(try{throw  . . .}catch(...){})
----------------------------------------------------------------------------------------------------------------
4、异常
    被throw抛出异常数据不受作用范围的限制,直到被捕获被处理为止,因此在捕获时可以通过引用来犯访问异常数据。即使已经被处理的异常数据,也可以用一个不带数据的throw重新抛出。
    如果抛出的异常没有被捕获处理,系统会调用terminate()函数终止程序。set_terminate(func)可以指定在terminate时自动调用func函数。
    异常传递机制:从throw开始离开正常执行流程,在本函数内找有没有包含它的try{}块,如果有,就依次查找它的catch块直到第一个类型匹配为止进入这个catch块执行处理,之后从最后一个catch块之后继续执行;如果没有包含它的try{}块或者没有类型匹配的catch块,异常数据继续传递到上层函数(调用它的那个函数)中重复这个过程,如果直到main函数还没有完成处理,系统就调用terminate终止程序了。
    多个catch块如果同时有父类类型和子类类型,应该把子类类型的放在前面,如果有一个是catch( . . . ),它必须放在最后。


    异常声明:一个函数可以声明自己可能抛出哪些类型的异常,格式为:
            返回类型  函数名 (参数表) throw(异常类型列表);
            int  func(int  a[ ],int  idx) throw (double, int, string);
    如果在函数内部抛出了不在列表中的异常,则会引发意外。可以通过set_unexpected(func)来设置遇到意外情况时调用func。没有异常声明表示可能抛出任何类型的异常,空异常列表表示不会抛出异常。




    标准异常:exception 类,#include< exception >
    定义子类覆盖父类的虚函数时,异常声明的内容不能超出父类中这个函数的异常声明内容。
    标准库中抛出的异常类型都是exception类的子类。
    自己定义异常类型一般继承exception类,覆盖const  char * what( )  const  throw( )函数,返回一个字符串,描述发生了什么异常。


4、I/O  input/output
    标准库中的输入输出对象:
        cin:控制台输入console  input (标准输入)
        cout:控制台输出console  output (标准输出)
        cerr:错误输出,不缓冲,不重定向
        clog:跟cerr一样,
    类体系:
                                       | ---istringstream
                                       |
         |--- istream:cin  --  |--- ifstream 
         |                             |
ios -- |                             |
         |                             |---iostream  ---   fstream
         |                             |
         |--- ostream:cout --|--- ofstream
                                       |          
                                       |  ---ostringstream


    输入:
        格式化输入:把一系列字符转化成对应格式的数值保存咋变量中。
        ws去掉前导的空白字符(空格、制表符、换行符、回车符、换页符、垂直制表符),hex,dec,oct表示用几进制输入;
        cin >>  ws  >> hex >> n ;//65==> 0x65 ==> 101
        非格式化输入:保持原来的格式
                    get(),get(char  &)从输入流中读取一个字符,空白字符也照样取走。peek()查看但不去走,putback(char)把一个刚取
                走的字符送回输入流中(如果送回的不是刚取走的字符,系统不保证成功)。ignore(int  n=1, char  end=EOF)从输入流中丢弃
                n个字符,但如果提前遇到end就停止丢弃//EOF:end  of  file 
                    getline(char  数组, 数组大小)读取一行输入,如果输入超过最大长度,只读去最大长度 - 1个字符并追加'\0',并设置错误标志。
                处于错误状态下的IO对象不再执行IO操作,直到clear()清除错误状态为止。***注意clear只是清除错误状态,并不丢弃输入流中
                的字符,想丢弃输入流中的字符用ignore。getline(cin , string对象)则不存在超长问题。IO流对象都可以看成一个bool类型的
                数据,当处于正常状态时为真,处于错误状态时为假。
                while( cin  >> n ){ }  //输入出错时循环结束(不匹配,Ctrl+D)
                getline可以用第三个参数指定读到什么字符为止。
                cin.getline(buf, maxlen, end_char);
                getline(cin, stringobject,end_char);
                fail(),bad(),eof(),good()表示三种错误状态和没有出错。
    输出:
        格式化输出:把内存中的数值用一系列字符表示出来,比如:12345,在内存中是0x00003039[ 39  30  00  00 ],输出时转换成“12345”。cout << 12345;
        格式控制:setf( flag )/unsetf( flag )设置/取消标志。标志在ios中定义,使用时应该ios::标志。
               boolalpha, dec/hex/oct(三选一), left/right/internal(三选一), scientific/fixed(二选一)科学计数法/小数形式, showbase显示进制前缀(0x/0/无)showpoint显示小数点,  showpos显示正符号, uppercase在输出十六进制时的 x 和 a-f 以及科学计数法中的 e 用大写字母, unibuf每次输出后都刷新缓冲区。skipws输入时跳过空白字符。
        一般使用格式控制符取代标志。
        width(w)指定下一项输出占多少个字符的位置,如果实际数据超过指定宽度按实际数据宽度输出而不截断,而且宽度只对下一项有效。实际数据短则用空格填充。fill(c)可以指定用其它字符代替填充。precision(n)把小数的精度(有效数字)设置为n, 如果同时指定了fixed表示则表示小数点后的位数为n。


class  wf{
    int  w;
    char  f;
public:
    wf(int  w, char  f):w(w),f(f){}
    friend  ostream&  operator << (ostream & o,const  wf & x){
        o.width(x.w);
        o.fill(x.f);
        return o;
    }
};
cout<< wf(10,'#')<<123<<endl;
        非格式化输出: 
                put( c ), flush( stdout )。        


---------------------------------------------------------------------------------------------------------
#include <iostream>
#include <cctype>
using namespace std;
istream & func(istream &i)
{
char c;
do
{
i>>c;
}while(!isdigit(c));//取走非数字字符
i.putback(c);//退回一个字符
return i;//i 就是cin
}
int main(int argc, char *argv[])
{
int n=-1;
cin>>func>>n;
cout<<"n= "<<n<<endl;
return 0;
}
-------------------------------------------------------------------------------------------------------------


1、I/O
    字符串IO:把字符串当成键盘输入 >> 或者当成屏幕输出 <<。
        operator  <<
        #include < sstream >
        istringstream  in( const  string  & str  );
        in  >>  . . .
        ostringstream  out;
        out  <<  . . .
        out.str( ) 取得字符串
        通过它们可以再 string 类型和各种其它支持 << ,>> 的类型直接转换。
    文件IO:#include < fstream >
        ifstream      fin       文件输入流对象
        ofstream     fout     文件输出流对象
        fstream      fio        文件IO对象,输入输出都可以
        都是istream/ostream类的子类,cin/cout能做的事情,文件fin/fout都可以做。文件输入/输出流对象需要跟一个文件关联。
        方法1:xfstream  fs(文件路径,打开方式标志=默认值)
        方法2:xfsream   fs;  fs.open(文件路径,打开方式标志=默认值)
        两者都会打开文件,成功与否可以通过检测是否为真来判断,fs.is_open()。
        标志:ios::in读,ios::out写,ios::app追加,ios::trunc清空,ios::ate一开始在末尾(可以调到其它地方),输入流默认标志in,输出流对象默认标志out|trunc。
        读写:>>,<< ,get()/put(c),getline(),eof()判断是否遇到了文件末尾(最后一个字节的后面)。
        read(char *addr,  int  bytes)
        write(const  void * addr,  int  bytes)
        在文件和内存之间直接按原始格式(二进制格式)转存数据。
        close()关闭文件,释放资源,同时让缓冲区和磁盘文件的内容同步以免丢失文件内容。
        gcount()取得最后一次读取到的字节数。
        定位:
            seekp/seekg(偏移量)定位到离文件开始制定偏移量的位置,0表示就在开头。seekp/seekg(偏移量,参考基点),基点可以是ios::beg,ios::end,ios::粗人三选一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值