1、 第二章 为选读1.数据成员-不能初始化2.成员函数-可以使用类中的所有成员(变量和函数)1声明与实现都定义在类内部 2声明在类内部,实现在类外部3.private-1类内可以被访问 2类外不能被直接访问,通过公有成员函数访问 3默认类型(数据成员常用)4继承关系中,子类不可以访问父类的 private 成员4.protected-1类内可以被访问 2类外不能被直接访问,通过公有成员函数访问 3继承关系中,子类可以访问父类的 protected 成员5.public-1类内和类外都可以被访问 2成员函数常用6.构造函数-1特殊的类成员函数为新对象分配内存空间 2功能:为新对象分配内存空间;初始
2、化数据成员 3写法:a.构造函数名与类名相同 b.没有返回时值类型 c.可以重载d.一般为 public(例如:在成员函数里生成对象,可以为私有)4使用:声明对象(或需要构造新对象)时系统自动调用 5默认构造函数 (只有一个,无参数/每个参数都有默认值,无函数体)7.析构函数-1特殊的类成员函数,回收内存空间 2功能:撤销类的对象 3写法:a.析构函数名与类名相同,前面冠以 b.没有参数,返回时值类型 c.不可以重载,只有一个 d.公有 4使用:撤销对象时系统自动调用 5默认析构函数 (只有一个,无参数/每个参数都有默认值,无函数体)构造函数与析构函数调用顺序:先构造后析构,后构造先析构8.引
3、用-1已经定义的变量的别名,不为其分配内存空间 2&是引用类型说明符 3声明引用时,必须同时对其进行初始,且不能再把该引用名作为其他变量名的别别名 4不能建立数组的引用,只能建立数组元素的引用。5使用:a.引用作为函数参数-类似于地址传值 b.引用作为函数返回值-一般函数返回值时,要生成一个临时变量作为返回值的副本,而用引用作为返回值时,不生成值的副本。注意:引用作为函数的返回值的情况:I.全局变量 II.引用参数传递过来的变量#不能是函数中的局部变量,这时返回的局部变量地址已经失效。9.复制构造函数:特殊的构造函数1功能:用一个已经存在的对象去初始化一个新的同类对象 2写法:a.函数名与类名
4、相同 b.形参是本类对象的引用,无返回值类型 c.默认拷贝构造函数/自定义拷贝构造函数3以下情况时,系统自动调用复制构造函数a.用一个对象初始化另一个对象 b.函数形参是类的对象,函数形参和实参结合时 c.函数返回值是类的对象,当函数返回时10.成员对象与构造函数1定义:类中的成员,除了成员数据和成员函数外,还有成员对象,即用其他类的对象作为类的成员,也称为对象成员,使用成员对象的技术称为聚合。成员对象是实体,系统不仅为它分配内存,而且要进行初始化。2构造函数写法:a.类名类名:构造函数名构造函数名(参数总表参数总表):对象成员对象成员 1(参数名表参数名表 1),对象成员,对象成员2(参数名
5、表参数名表 2),对象成员对象成员 n(参数名表参数名表 n)/参数总表:含数据类型;参数名表:不含数据类型参数总表:含数据类型;参数名表:不含数据类型b.构造函数可以采用多种方法对数据成员初始化:在构造函数体中初始化 在构造函数头部初始化 混合初始化3构造函数调用顺序:含对象成员的类对象的初始化时,首先依次自动调用各成员对象的构造函数,再执行该类对象自己的构造函数的函数体部分。各成员对象的构造函数调用的次序与类定义中说明的顺序一致,而与它们在构造函数成员初始化列表中的顺序无关。4析构函数调用顺序:因为析构函数没有参数,所以包含成员对象的类的析构函数形式上并无特殊之处。但是撤销该类对象时,会首
6、先调用自己的析构函数,再调用成员对象的析构函数,调用次序与初始化时的次序相反。11.运算符重载1定义:运算符的重载是特殊的函数重载,必须定义一个函数,并通知 C+编译器,当遇到该重载的运算符时调用此函数。对运算符进行定义叫做运算符重载函数,通常为类的成员函数。2写法:a.返回值类型返回值类型 operator 重载的运算符重载的运算符(参数表参数表)/operator 是关键字,它与重载的运算符一起构成函数名。是关键字,它与重载的运算符一起构成函数名。b.引用作为参数:const 引用Complex operator+(const Complex&c)注意:参数采用对象的引用而不是对象本身,调
7、用时不再重新分配内存建立一个复制的对象,函数效率会更高。而在引用形式参数类型说明前加 const 关键字,表示被引用的实参是不可改变的,如程序员不当心在函数体中重新赋值了被引用的实参,C+编译器会认为出错。附加:const 引用可以实现不可寻址的值,或不同数据类型的引用 const int&q=7;q 的值不能变 int p=3;const double&q=p;=double t=p;const double&q=t;/t 为临时变量3实现:运算符的左操作数一定是对象,因为重载的运算符是该对象的成员函数,而右操作数是该函数的参数。c3=c1+c2 解释为:解释为:c1.operator+(c
8、2);用标示符用标示符 temp 表示返回的临时变量,表示返回的临时变量,c3=temp,解释为:解释为:c3.operator=(temp)4默认的赋值重载运算符Complex&operator+(const Complex&c)/返回值类型是为了 a=b=c 的形式5右操作数不是类的对象 c3=c1+0.6;c3=0.6+c1;(错误错误,用友元解用友元解决决)Complex operator+(const Complex&c)或 Complex operator+(double c)6不允许重载的运算符?:./.*:sizeof12.友元 1定义:某一个类的友元(friend)函数不属于
9、该类,但可以在类外访问该类中的任何成员,包括私有数据。友元函数用关键字 friend 说明。2写法:friend complex operator+(const complex&c1,const complex&c2)/“const 引用”作为参数,可以实现:a+0.6;0.6+a;a+b 3说明:a.friend 只用于类说明中,定义时不加 friendb.注意友元不是成员函数,但可以直接访问私有成员c.d+c 被 C+编译器解释为:operator+(d,c)d.友元函数不受类中的访问权限关键字限制,可以把它放在类的公有、私有、保护部分,但结果一样。4 运算符重载的三种形式成员函数成员函数
10、形式形式CInt operator+(const CInt&r);友元函数友元函数形式形式friend CInt operator+(const Cint&r1,const CInt&r2);全局函数全局函数形式形式CInt operator+(const Cint&r1,const CInt&r2);函数调用函数调用特点特点说明说明成员函数成员函数形式形式a.operator+(b)1.定义为类的成员函数定义为类的成员函数2.左操作数必须是类的左操作数必须是类的对象对象3.右操作数设为函数参右操作数设为函数参数数1.左操作数作为当前对象通过左操作数作为当前对象通过 this 指针访指针访问问
11、2.右操作数通过函数参数访问右操作数通过函数参数访问友元函数友元函数形式形式operator+(a,b)1.定义为类的友元函数定义为类的友元函数2.左操作数不一定是类左操作数不一定是类的对象的对象3.左右操作数按顺序作左右操作数按顺序作为函数的参数为函数的参数1.作为类的友元直接访问对象的私有数据作为类的友元直接访问对象的私有数据成员成员2.有些运算符的参数只能为特定类型,如,有些运算符的参数只能为特定类型,如,流插入运算符流插入运算符”只能重载为类的成员函数的运算符:赋值运算符赋值运算符=复合赋值运算符复合赋值运算符+=,-=,*=,/=函数调用运算符函数调用运算符()下标运算符下标运算符成
12、员访问运算符成员访问运算符-13.静态成员:是指声明为 static 的类成员1在类的范围内所有对象共享的某个数据,静态数据成员不属于类的某一特定对象,而是属于整个类。2无论私有或非私有,必须在类外初始化,用(:)来指明所属的类。3静态成员函数只能直接访问类中的静态成员。4非静态成员时,必须借助对象名或指向对象的指针。5静态成员(变量和函数)可以用类名或对象名访问。14.指针:1指向对象的指针-引用成员方式:-或 *.补充 a.指向 const 对象的指针:const int i=9;const int*p=&i;/允许给 p 指针重新赋值,使其指向另一个 const 对象,但是不允许通过 p
13、 指针来修改所指对象的值。b.const 指针:int i=0;int*const p=&i;/const 指针的值是不能被修改的,这意味着不能使其指向其他的对象。所以在定义的时候就必须要初始化。c.指向 const 对象的 const 指针:const i=10;const int*const p=&i;/既不能修改指针 p 所指向的对象的值,也不允许修改该指针 p 的指向2this 指针a.定义:只能在一个类的成员函数中调用,它表示当前对象的地址b.使用:(1)数据成员与成员函数参数同名时 (2)成员函数返回值时当前类的对象15.string 类 C+的字符串 string 类,它重载了运
14、算符,连接、索引和复制等操作不必使用函数,使运算更加方便,而且不易出错。#includeusing namespace std;16.多文件结构模板模板通用的代码就必须不受数据类型的限制,可以把数据类型改为一个设计通用的代码就必须不受数据类型的限制,可以把数据类型改为一个设计参数。这种类型的程序设计称为参数化参数。这种类型的程序设计称为参数化(parameterize)程序设计。程序设计。17.函数模板:1定义:用来创建一个通用函数,支持多种不同类型形参。2写法:template返回类型 函数名(形式参数表)/尖括号中不能为空,参数可以有多个,用逗号分开。/由关键字 class 或 typen
15、ame(建议用 typename)后加一个标识符构成。3使用:使用函数模板,只需以函数模板名为函数名进行函数调用:函数名(数据实参表);18.类模板:1写法:template class 类名;template 返回类型 类名:成员函数名(形参表)2说明:a.类模板的定义格式与类相同,包含数据成员与成员函数b.类模板中的成员函数都是函数模板c.函数声明(声明与定义分开)时不加“template”d.模板参数有两种:模板类型参数和模板非类型参数。3使用:类模板名 对象名(初始化参数表)4模板非类型参数:表示该参数名代表了一个常量。19.模板与类参数:在面向对象程序设计中,函数模板有两种常见的应用
16、方式:1函数模板作为类模板的成员函数,在模板类型参数中重载函数与运算符,直接访问私有数据成员,实现通用算法。2独立的函数模板(非成员函数)处理模板类(或普通类,或普通数据),以类模板为参数,借助模板类型参数中重载的函数或运算符实现通用算法。20.动态内存分配 1动态分配与释放a.分配:当程序运行到需要动态分配变量或对象时,必须向系统申请取得自由存储区中的一块所需大小的存储空间,用于存储该变量或对象。指针变量名=new 类型名(初始化式);b.释放:当不再使用该变量或对象时,也就是它的生命结束时,要显式释放它所占用的存储空间,这样系统就能进行再次分配,做到重复使用有限的资源。delete 指针名
17、;/这时释放了 pi 所指的目标的内存空间,也就是撤销了该目标,称动态内存释放,但指针 pi 本身并没有撤销,该指针所占内存空间并未释放。C.数组的动态内存分配指针变量名=new 类型名下标表达式;/“下标表达式”可以是变量表达式char*pc;int n;cinn;/动态数组个数动态数组个数pc=new charn;/申请内存申请内存strcpy(pc,”china”);delete pc;/释放内存释放内存delete 指向该数组的指针变量名;特点:i.”下标表达式”可以在运行时确定 ii.如果有 char*pc1,令 pc1=pc,同样可用 delete pc1 来 释放该空间。iii.
18、没有初始化式,不可对数组初始化。2自由存储区对象与构造函数 通过 new 建立的对象要调用构造函数,通过 delete 删除对象也要调用析构函数。3浅复制与深复制a.浅复制:默认复制构造函数,可用一个类对象初始化另一个类对象,称为默认的按成员复制,而不是对整个类对象的按位复制。这称为浅复制。b.深复制:重新定义复制的构造函数,给每个对象独立分配一个自由存储区对象,称深复制。21.继承1定义:被继承的类称为基类(base class)或超类(superclass),新的类为派生类(derived class)或子类(subclass)。2写法:派生类的定义:class 派生类名:访问限定符 基类
19、名 1,访问限定符 基类名 2,访问限定符 基类名 n private:成员表 1;/派生类增加或替代的私有成员public:成员表 2;/派生类增加或替代的公有成员protected:成员表 3;/派生类增加或替代的保护成员;3访问限定符:公有派生是绝对主流继承方式继承方式基类特性基类特性派生类特性派生类特性(派生类中对基类成员的访问限定(派生类中对基类成员的访问限定)在派生类对象访问基类成员在派生类对象访问基类成员 publicpublic可访问可访问protectedprotected不可访问不可访问公有继承公有继承private不可访问不可访问不可访问不可访问publicprivate
20、不可访问不可访问protectedprivate不可访问不可访问私有继承私有继承private不可访问不可访问不可访问不可访问publicprotected不可访问不可访问protectedprotected不可访问不可访问保护继承保护继承private不可访问不可访问不可访问不可访问4派生类构造函数派生类名(参数总表):基类名 1(参数名表 1),基类名 2(参数名表 2),基类名 n(参数名表 n),成员对象名 1(成员对象参数名表 1),成员对象名 m(成员对象参数名表 m)/派生类新增成员的初始化;/所列出的成员对象名全部为新增成员对象的名字5派生类构造函数各部分执行次序:a.调用基类
21、构造函数,按它们在派生类定义的先后顺序,顺序调用。b.调用成员对象的构造函数,按它们在类定义中声明的先后顺序调用。c.派生类的构造函数体中的操作。/注意:1.如果基类没有定义构造函数,则派生类也可以不定义,全部采用系统给定的默认构造函数。2.如果基类定义了带有形参表的构造函数时,派生类就应当定义构造函数,显式给出基类名和参数表。6析构函数调用次序与构造函数相反22.多重继承1基类构造函数的调用顺序:a.派生类构造函数执行顺序是先执行所有基类的构造函数,再执行派生类本身构造函数。b.处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列
22、表的顺序无关。多继承时的重名成员:2在多个基类中有重名的成员:使用作用域运算符:访问重名的成员23.虚基类1引入:a.多继承时,发生了重名成员。且这些重名成员来自同一个间接基类。b.将共同基类设置为虚基类,从不同路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。2写法:class 派生类名派生类名:virtual 访问限定符访问限定符 基类类名基类类名.;class 派生类名派生类名:访问限定符访问限定符 virtual 基类类名基类类名.;3构造函数:派生类名派生类名(参数总表参数总表):基类名基类名 1(参数名表参数名表 1),成员对象名成员对象名 1(成员对象
23、成员对象参数名表参数名表 1),,底层虚基类名底层虚基类名 1(参数名表参数名表 1),底层虚基类名底层虚基类名 r(参参数名表数名表 r);/在多层虚拟继承构造函数中,基类名不仅要列出直接基类,而且要列出底层虚基类,否则编译器认为出错。如不是虚拟继承只能列直接基类。4构造函数调用顺序首先是虚基类的构造函数并按它们声明的顺序构造。第二是非虚基类的构造函数按它们声明的顺序调用。第三是成员对象的构造函数。最后是派生类自己的构造函数被调用。24派生类应用讨论1派生时的同名覆盖:a.数据成员的同名覆盖b.成员函数的同名覆盖c.使用作用域运算符:访问被覆盖的成员2 赋值兼容规则:在任何需要基类对象的地方
24、都可以用公有派生类的对象来代替:a.派生类的对象可以赋值给基类的对象,这时是把派生类对象中从对应基类中继承来的成员赋值给基类对象。反过来不行,因为派生类的新成员无值可赋。b.可以将一个派生类的对象的地址赋给其基类的指针变量,但只能通过这个指针访问派生类中由基类继承来的成员,不能访问派生类中的新成员。同样也不能反过来做。c.派生类对象可以初始化基类的引用。引用是别名,但这个别名只能包含派生类对象中的由基类继承来的成员。3继承与聚合:继承使派生类可以利用基类的成员,如果我们把基类的对象作为一个新类的对象成员,也可以取得类似的效果。派生类采用继承方法,成员对象是聚合的概念。4派生类与模板:模板追求的
25、是运行效率,而派生追求的是编程的效率。25多态性与虚函数在在C+中有中有两种多态性两种多态性 编译时的多态性编译时的多态性 运行时的多态运行时的多态性性 运行时的多态性是指在程序执行前,无法根据运行时的多态性是指在程序执行前,无法根据函数名和参数来确定该调用哪一个函数,必须函数名和参数来确定该调用哪一个函数,必须在程序执行过程中,根据执行的具体情况来动在程序执行过程中,根据执行的具体情况来动态地确定。它是态地确定。它是通通过过类继类继承关系和虚函数承关系和虚函数来来实实现现的。的。目的也是建立一种通用的程序。目的也是建立一种通用的程序。通用性是通用性是程序追求的主要目程序追求的主要目标标之一。
26、之一。通通过过函数的重函数的重载载和运算符的重和运算符的重载载来来实现实现的。的。1 虚函数:virtual 返回类型返回类型 函数名(参数表)函数名(参数表)/关键字 virtual 指明该成员函数为虚函数。virtual 仅用于类定义中,如虚函数在类外定义,不可再加 virtual。/当一个类的某个成员函数被定义为虚函数,则由该类派生出来的所有派生类中,该函数始终保持虚函数的特征。2成员函数设置为虚函数的要点:a.派生类中定义虚函数必须与基类中的虚函数同名外,还必须同参数表,同返回类型。否则被认为是重载,而不是虚函数。b.只有类的成员函数才能说明为虚函数,这是因为虚函数仅适用于有继承关系的
27、类对象。c.静态成员函数和内联函数,不能作为虚函数。d.一个类对象的静态和动态构造是相同的,实现动态多态性时,必须使必须使用基类类型的指针变量或引用用基类类型的指针变量或引用,使该指针指向该基类的不同派生类的对象,并通过该指针指向虚函数,才能实现动态的多态性。e.析构函数可定义为虚函数,构造函数不能定义虚函数,因为在调用构造函数时对象还没有完成实例化。通常把析构函数定义为虚函数,实现撤消对象时的多态性。g.函数执行速度要稍慢一些。为了实现多态性,每一个派生类中均要保存相应虚函数的入口地址表,函数的调用机制也是间接实现。所以多态性总是要付出一定代价,但通用性是一个更高的目标。3纯虚函数:a.定义:是指被标明为不具体实现的虚拟成员函数。它用于这样的情况:定义一个基类时,会遇到无法定义基类中虚函数的具体实现,其实现依赖于不同的派生类。b.写法:virtual 返回类型 函数名(参数表)=0;c.含有纯虚函数的基类是不能用来定义对象的。纯虚函数没有实现部分,不能产生对象,所以含有纯虚函数的类是抽象类。