钱能2 1.docx
- 文档编号:30443222
- 上传时间:2023-08-15
- 格式:DOCX
- 页数:38
- 大小:94.80KB
钱能2 1.docx
《钱能2 1.docx》由会员分享,可在线阅读,更多相关《钱能2 1.docx(38页珍藏版)》请在冰豆网上搜索。
钱能21
面向对象技术(O-O技术)第二讲2009.3.27
例2.构造类成员——类成员初始化
(1)未使用冒号语法
#include
#include
classStudentID
{
public:
StudentID(intid=0)
{
value=id;
cout<<”Assigningstudentid”< } ~StudentID() {cout<<”Destructingid”< protected: intvalue; }; classStudent { public: Student(Char*pName=”noName”,intssID=0) { cout<<”Constructingstudent”< strncpy(name,pName,sizeof(name)); name[sizeof(name)-1]=’\0’; StudentIDid(ssID);//希望将学号传给学号类对象 } protected: charname[20]; StudentIDid; }; voidmain() { Students(“Randy”,9818); } 运行结果为: Assigningstudentid0 ConstructingstudentRandy Assigningstudentid9818 Destructingid9818 Destructingid0 (2)使用冒号语法——冒号表示显式调用类的数据成员(类成员)构造函数进行初始化; 1)修改 (1)程序; 2)运行结果: Assigningstudentid9818 ConstructingstudentRandy Assigningstudentid0 ConstructingstudentJenny Destructingid0 Destructingid9818 3)常量和引用的初始化必须放在构造函数的冒号后面; 一般变量的初始化可放在冒号后面,也可放在函数体中; classSillyClass { public: SillyClass(int&i): ten(10),refI(i){} protected: Constintten; int&refI; }; voidmain() { inti; SillyClasssc(i); } classSillyClass1 { public: SillyClass1() { d=10; } protected: intd; }; classSillyClass2 { public: SillyClass2(): d(10){} protected: intd; }; 例3.浅拷贝与深拷贝——用一个含堆成员的对象去构造另一个(堆)对象的拷贝构造函数。 (1)浅拷贝: 仅拷贝堆成员指针,并不复制堆成员(资源),仅类成员拷贝,并不拷贝相应的资源。 P1P1 拷贝前 P2 拷贝后 *运行错误 源程序: #include #include classPerson { public: Person(char*pN) { cout<<”Constructing“< pName=newchar[strlen(pN)+1]; if(pName! =0) {strcpy(pName,pN)} } ~Person() { cout<<”Destructing”< pName[0]=’\0’; deletepName; } protected: char*pName; }; voidmain() { Personp1(“Randy”); Personp2=p1; } 运行结果为: ConstructingRandy DestructingRandy Destructing Nullpointerassignment (2)深拷贝——不仅拷贝(堆)成员,而且拷贝堆成员(资源),即不仅拷贝类成员,而且拷贝相应的资源。 P1 P1 拷贝前 P2 拷贝后 源程序: #include #include classPerson { public: Person(char*pN); Person(Person&p); ~Person(); protected: char*pName; }; Person: : Person(char*pN) { cout<<”Constructing”< pName=newchar[strlen(pN)+1]; if(pName! =0) { strcpy(pName,pN); } } Person: : Person(Person&p) { cout<<”Copying“< pName=newchar[strlen(p.pName)+1]; if(pName! =0) strcpy(pName,p.pName); } Person: : ~Person() { cout<<”Destructing“< pName[0]=’\0’; deletepName; } voidmain() { Personp1(“Randy”); Personp2=p1; } 运行结果为: ConstructingRandy CopyingRandyintoitsownblock DestructingRandy DestructingRandy §2.3静态成员与友元 一.基本概念 1.静态成员(static) (1)静态数据成员: ①存放在全局数据区;②默认值为0,一次初始化;③属于类,不属于类实例;④具有公有/私有或保护存储控制说明符;⑤并且在类的成员函数定义中实现(类的内部实现部分中定义为好);⑥访问方式: 类名: : 静态成员(见书P335的例子)。 (2)静态成员函数: ①属于类,不属于类实例;②类类型: : 静态成员函数名; ③对静态数据成员的访问实现了文件内同类对象之间的通信;④定义位置: 与一般成员函数一样;⑤只认类型,不认对象;⑥静态成员函数没有this指针(与非静态成员函数的根本区别)。 2.友元(friend) (1)需要友元的原因: ①普通函数直接访问类的保护或私有数据成员,提高访问效率; ②为了方便重载操作符的使用,即方便编程。 (2)说明: ①友元函数不是类成员函数,它是类的朋友,因而能够访问类的全部成员; ②友元声明位置可以是在类的任何部位; ③友元函数定义则在类的外部,一般与类的成员函数定义放在一起;因为类重用时,一般友元是一起提供的。 ④友元破坏了类的整体操作性,也破坏了类的封装,使用时权衡利弊。 (3)类型 ①普通函数作为类的友元函数; ②一个类的成员函数可以是另一个类的友元; ③整个类是另一个类的友元,该友元称为友类。 3.实例分析 例1(见书p340) #include #include classStudent { public: Student(char*pName); ~Student(); staticStudent*findname(char*pName);//公共静态成员函数 protected: staticStudent*pFirst;//私有(保护)静态数据成员 Student*pNext; Charname[40]; }; Student*Student: : pFirst=0;//静态成员空间分配及初始化 Student: : : Student(char*pName) { strncpy(name,pName,sizeof(name)); name[sizeof(name)-1]=’\0’; pNext=pFirst; pFirst=this; } Student: : ~Student() { if(pFirst==this) { pFirst=pNext; return; } for(Student*pS=pFirst;pS;pS=pS->pNext) if(pS->pNext==this) { pS->pNext==pNext; return; } } Student*Student: : findname(char*pName) { for(Student*pS=pFirst;pS;pS=pS->pNext) if(strcmp(pS->name,pName)==0) {returnpS;} return(Student*)0; } voidmain() { Students1(“Randy”); Students2(“Jenny”); Students3(“Kinsey”); Student*pS=Student: : findname(“Jenny”); if(pS) cout<<”ok.”< else cout<<”nofind.”< } 运行结果为: ok. 例2友元与运算符重载 运算符重载的形式是: 返回类型operator运算符(参数说明); 1参数和返回类型可以重新说明,即可以重载。 2运算顺序和优先级不能更改。 3参数说明都是内部类型时,不能重载。 4“。 、: : 、*、->、? ”五种运算符不能重载,也不能创造新运算符。 实例分析: (见书p407) #include classIncrease { public: Increase(intx): value(x){} friendIncrease&operator++(Increase&);//前增量 friendIncreaseoperator++(Increase&,int);//后增量 voiddisplay() { cout<<”thevalueis“< } private: intvalue; }; Increase&operator++(Increase&a) { a.value++;//前增量 returna;//再返回原对象 } Increaseoperator++(Increase&a,int) { Increasetemp(a);//通过拷贝构造函数保存原有对象值 a.value++;//原有对象增量修改 returntemp;//返回原有对象值 } voidmain() { Increasen(20); n.display(); (n++).display();//显示临时对象值 n.display();//显示原有对象 ++n; n.display(); ++(++n); n.display(); (n++)++;//第二次增量操作对临时对象进行 n.display(); } 运行结果为: thevalueis20 thevalueis20 thevalueis21 thevalueis22 thevalueis24 thevalueis25 调用形式: 对象名.operator++() 对象名.operator++(int) 对象名++/++对象名 讨论: 1.改为类成员形式的定义 1Increase&Increase: : operator++(); 2IncreaseIncrease: : operator++(int); 2.重载赋值运算符与默认赋值运算符 (1)定义格式: Myclass&operator=(Myclass&s) (2)默认赋值运算符(重载): 浅拷贝; (3)与拷贝构造函数的区别 1voidfu(Myclass&mc) { MyclassnewMc=mc;//这是拷贝构造函数(newMc对象还不存在时); newMc=mc;//这是重载赋值运算符(已经存在newMc对象时); …应用未定义时,使用默认重载赋值运算符; } 2classmyclass { myclassmc1(a,b,c); myclassmc2=mc1; myclassmc3(mc2); … } 3.使用方式 (1)运算符使用方式: Myclasss1(a,b,c); Myclasss2; s2=s1; (2)函数调用方式: s2.operator=(s1); 实例见书p411—412,不讲了,自己看即可。 #include #include className { public: Name() { pName=0; } Name(char*pn) { copyName(pn); } Name(Name&s) { copyName(s.pName); } ~Name() { deleteName(); } Name&operator=(Name&s) { deleteName(); copyName(s.pName); return*this; } voiddisplay() { cout< } protected: voidcopyName(char*pN); voiddeleteName(); char*pName; }; voidName: : copyName(char*pN) { pName=newchar[strlen(pN)+1]; if(pName) { strcpy(pName,pN); } } voidName: : deleteName() { if(pName) { deletepName; pName=0; } } voidmain() { Names(“Claudette”); Namet(“temporary”); t.display(); t=s; t.display();//赋值 } 运行结果为: temporary Claudette §2.4类继承与虚函数机制 一.基本概念 1.继承方式 class<类名>: <访问控制符><基类名> 其中: 访问控制符的语义如下表所示 (1) 基类存取类型 子类继承类型 public protected private public public/可访 protected/可访 private/不可访 protected protected/可访 protected/可访 private/不可访 private private/可访 private/可访 private/不可访 (2)实例见书p389. classBase { public: intm1; protected: intm2; private: intm3; }; classPrivateClass: privateBase//私有继承 { public: voidtest() { m1=1;//ok: 将m1据为private m2=2;//ok: 将m2据为private m3=3;//不可访问 } }; classDerivedFromPri: publicPrivateClass { public: voidtest() { m1=1;//不可访问基类的私有成员 m2=2;//不可访问 m3=3;//不可访问 } }; classProtectedClass: protectedBase { public: voidtest() { m1=1;//m1据为protected m2=2;//m2据为protected m3=3;//不可访问 } }; classDerivedFromPro: publicProtectedClass { public: voidtest() { m1=1;//m1仍为protected m2=2;//m2仍为protected m3=3;//不可访问 } }; classPublicClass: publicBase//公共继承 { public: voidtest() { m1=1;//m1为public m2=2;//m2为protected m3=3;//不可访问 } }; classDerivedFromPub: publicPublicClass { public: voidtest() { m1=1;//m1仍保持为public m2=2;//m2仍保持为protected m3=3;//不可访问 } }; voidmain() { PrivateClasspriObj; PriObj.m1=1;//error PriObj.m2=2;//error PriObj.m2=2;//error ProtectedClassproObj; Probj.m1=1;//error ProObj.m2=2;//error ProObj.m3=3;//error PublicClasspubObj; PubObj.m1=1; PubObj.m2=2;//error PubObj.m3=3;//error } (3)protected与private的主要区别 1在单个类中,无区别; 2在继承关系中有区别: 基类的private成员不但对应用程序隐藏,甚至对派生类也隐瞒; 基类的protected成员只对应用程序隐藏,而对派生类则毫不隐瞒。 2.构造函数与析构函数 (1) 单继承: 按派生类次序构造,按构造的相反次序析构;即 (2)多继承: 按派生类次序(从左向右,从上到下)构造, 按构造的相反次序(从右到左,从下到上)析构。 例1: classb: publica{}例2: classd: publicc, publicb {} 3.多态性: 在运行时,能依据其对象的类型确认哪个函数的能力,称为多态性或迟后联编,实现动态(后期)绑定。 4.面向对象与基于对象的区别: 前者语言支持多态,后者语言支持类而不支持多态(如Ada,VB)。 5.虚函数限制: ①类的成员函数才能说明为虚函数; ②静态成员函数不能是虚函数; ③内联(inline)函数不能是虚函数 ④构造函数不能是虚函数; 5析构函数可以是虚函数,而且通常声明为虚函数。 6.类的冗余和类的分解 。 将共有特征提取出来的过程称为分解(factoring); 。 分解使类的层次合理化和减少冗余; (1)银行存款问题: (储蓄类)(存款类) *取款操作Withdrawal()也与存储,存款类的取款操作不同; (2).解决方法 方法 (一): Checking类作为Savings类的一个派生 讨论: ①结算帐户是储蓄帐户的一个特殊类型,但事实不为如此; 即两类用户合二为一链表: ②银行允许储蓄帐号的余额可以出现允许的范围的负数(一定程度的透支) ·minbalance(透支范围)数据成负; ·并修改withdrawal()虚函数; ③问题checking类也得到了minbalance这个新的数据成员,但对其无用的,增加混淆。 方法 (二)为了避免上述方法(-)的问题,另建一个新类(基类)法;并让这两个类都基于新类之上; 二.实例分析(见书p358): 例1.单继承与虚函数 #include classBase { public: virtualvoidfn() {cout<<”InBaseClass\n”} }; classsubclass: publicBase { public: virtualvoidfn() {cout<<”InSubclass\n”;} }; voidtest(Base&b) { b.fn();//∴“迟后联编∵fn()Virtual(编译时)“ } voidmain() { Basebc; Subclasssc; cout<<”callingtest(bc)\n”; test(bc); cout<<”callingtest(sc)\n”; test(sc); } 运行结果为: callingtest(bc) InBaseclass Callingtest(sc) InSubclass 例2继承的访问控制符与派生类数据空间 (1) classBase { public: intm1; protected: intm2; private: intm3; }; classPrivateClass: privateBase//私有继承 { public: voidtest() { m1=1;//ok: 将m1据为private
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 钱能2
![提示](https://static.bdocx.com/images/bang_tan.gif)