oolecture9.docx
- 文档编号:29658503
- 上传时间:2023-07-26
- 格式:DOCX
- 页数:28
- 大小:32.38KB
oolecture9.docx
《oolecture9.docx》由会员分享,可在线阅读,更多相关《oolecture9.docx(28页珍藏版)》请在冰豆网上搜索。
oolecture9
十二.对象间关系模型的实现
对象模型的三种关系都可以在C++和C#语言得到支持,但能够体现在语法上的只有对象模型中继承(派生)关系。
⒈聚合关系
1复合(不透明)聚合
例1:
C++语言示例
#include
usingnamespacestd;
classA
{
inti;
public:
A(){i=0;}
A(intx):
i(x){}
intoperator!
(){returni;}
};
classB
{
intj;
A*p;
public:
B(intx):
j(x){p=newA[x];}
intoperator!
(){returnj;}
voidoperator~(){for(inti=0;i p[i];} }; voidmain() { Bb(10); cout< b< ~b; } 例2: C#语言示例 usingSystem; classA { inti; publicA(){i=0;} publicA(intx){i=x;} publicstaticintoperator! (Ax){returnx.i;} staticvoidMain() { Bb=newB(10); Console.Write(! b); inti=~b; } }; classB { intj; A[]p; publicB(intx) { p=newA[x];//只初始化引用的数量,不会调A的缺省构造 for(intk=0;k j=x; } publicstaticintoperator! (Bx){returnx.j;} publicstaticintoperator~(Bx) { for(inti=0;i x.p[i]); return1; } }; 面向对象技术常利用聚合结构实现可变数组的结构设计。 在C++语言中,可以用算符函数配合;在C#语言中则可以依托系统命名空间中的Array对象辅以索引器来实现。 例3: C++语言示例 #include usingnamespacestd; classA { inti; A*array; public: A(intx=0): i(x){array=newA[x];for(intj=0;j A&operator[](intx){returnarray[x];} voidoperator=(intx){i=x;} intoperator! (){returni;} }; voidmain() { Aa(5); a[2]=3;//等价于(a.operator[] (2)).operator=(3); cout< a[2];//等价于什么? cin.get(); } 例4: C#语言示例 usingSystem; classA { inti; Arrayarray; publicA(intx) { i=x; array=Array.CreateInstance(typeof(object),i);//创建Array对象 } publicobjectthis[intx]//设置索引器 { get{returnarray.GetValue(x);} set{array.SetValue(x+1,x);} } staticvoidMain() { Aa=newA(5); for(inti=0;i<5;i++)a[i]=i;//呼叫索引器中set过程 Console.Write(a[2]);//呼叫索引器中get过程 } }; 2嵌入(透明)聚合 例5: C++语言示例—向对象单向链表中插入已有的对象 #include usingnamespacestd; classA { inti; A*next; public: A(intx,A*s=NULL): i(x),next(s){} A*GetNext(){returnnext;} voidSetNext(A*s){next=s;} intoperator! (){returni;} }; classB { intj; A*p; public: B(intx,A*s=NULL): j(x),p(s){} voidInsert(A*s) { if(! p)p=s; else { A*temp=p; while(temp->GetNext())temp=temp->GetNext(); temp->SetNext(s); } } intoperator! (){returnj;} voidoperator~() { A*temp=p; while(temp) { cout< (*temp)< temp=temp->GetNext(); } } }; voidmain() { Aa1(0),a2 (1),a3 (2); Bb(10,&a1); b.Insert(&a2); b.Insert(&a3); ! a1; ~b;//转发消息 cin.get(); } 例6: C#语言示例—向一个对象中插入另一个对象数组 usingSystem; classA { inti; publicB[]p; publicA(){i=0;} publicA(B[]x,inty) { p=newB[y]; for(intk=0;k i=y; } publicstaticintoperator! (Ax){returnx.i;} publicstaticintoperator~(Ax) { for(intk=0;k x.p[k]); return1; } staticvoidMain() { B[]b=newB[10]; for(intk=0;k<10;k++) { b[k]=newB(k); Console.Write(! b[k]);//直接发消息 } Aa=newA(b,10); Console.WriteLine(""); inti=~a;//转发消息 } }; classB { intj; publicB(intx){j=x;} publicstaticintoperator! (Bx){returnx.j;} }; ③类模板 用C++语言设计聚合结构的代码时,当被聚合的类的类型不确定时,可以用类模板来声明聚合关系。 其声明格式为: template class体声明; 类模板参数表内可以声明多个模板参数,但若其内部存在的模板参是另外一个亦被声明为类模板的类,则务使模板参数自左向右排放。 例7: template classA { Ti; public: A(Tx): i(x){} }; 例8: #include usingnamespacestd; template classArray { T*ar; public: Array(intc){ar=newT[c];} voidinit(intn,Tx){ar[n]=x;} T&operator[](intn){returnar[n];} }; voidmain() { Array cout<<"Pleaseinputeveryelement'svalue: "< for(inti=0;i<5;i++) { cout<<"No."< '; cin>>array[i]; } } 同不支持函数模板技术一样,C#语言不支持类模板技术。 ⒉继承(派生)关系 在C++语言和C#语言中分别有专用的语句来支持继承(派生)关系。 C++语言的定义的语法格式为: public类名i class类名1: protected类名j{成员声明}; private类名k C#语言的定义的语法格式为: class类名1: 类名2{成员声明}; 例9: C++语言示例 classA { protected: inti; public: A(intx): i(x){} }; classB: publicA { intj; public: B(intx,inty): j(x),A(y){} }; voidmain() { Bb(1,2); } 例10: C#语言示例 usingSystem; classA { inti; publicA(intx){i=x;} publicstaticintoperator! (Ax){returnx.i;} staticvoidMain() { Bb=newB(1,2); Console.Write(! b); Console.Write(! (A)b); inti=~b; } }; classB: A { intj; Ap; publicB(intx,inty): base(y){j=x;p=(A)this;} publicstaticintoperator! (Bx){returnx.j;} publicstaticintoperator~(Bx){Console.Write(! x.p);return1;} }; 使用继承时的一些规则: ①基类成员在被继承后的访问权限 ·public区的成员可以被部分或全部的继承并被派生类对象成员直接访问; ·protected区的成员在本类对象中的访问权限与同类private区的成员相同,且可以被部分或全部的继承并被派生类对象成员直接访问; ·private区的成员不能被派生类对象成员直接访问; ②C++语言中三种继承方式的作用 派生类中以public方式继承 派生类中以private方式继承 派生类中以protected方式继承 public public private protected protected protected private protected private - - - 由于存在上述三种继承方式,C++语言的继承/派生关系可能导致派生类对象成员彻底失去对其继承的基类成员的访问权利: 基类A ↓以private方式继承 派生类B ↓以任何方式继承 派生类C(失去对其基类A的成员的直接访问权利) C#语言中没有继承方式的设置,而是依靠基类对象成员自身的访问附加类别来实现派生类对象对继承得到的基类对象成员的访问权的。 而且因成员具有不同的访问附加类别声明,继承的也不一样。 ③C++语言中的派生类不继承基类中声明的友元 ④派生类对象中基类成员的初始化 派生类对象在自身初始化时必须通过成员初始化表(在C#语言中使用“: base(参数表)”)对其继承的基类对象进行初始化,且此种初始化要先于派生类对象本身的初始化。 例11: C++语言示例 classA { protected: inti; public: A(intx): i(x){} }; classB: publicA { intj; public: B(intx,inty): j(x),A(y){} }; voidmain() { Bb(1,2); } 在例10中的B类中的“publicB(intx,inty): base(y){j=x;p=(A)this;}”语句中,“: base(y)”可以被视为C#语言的成员初始化表的一种特例,但此处是直接指向了基类A的构造函数的。 ⑤成员覆盖(Memberoverridden) 若在派生类中声明了与基类同名的成员且又同时继承了基类的同名成员的情景称为成员覆盖。 在非多态的条件下对被覆盖的成员的引用是通过对象作用域来确定的。 在C#语言中的派生类中要用new附加类别显式声明覆盖的发生。 例12: C++语言示例 #include usingnamespacestd; classA { protected: inti; public: A(intx=0): i(x){} intoperator! (){returni;} }; classB: publicA { protected: inti; public: B(intx=0,inty=0): i(x),A(y){} intoperator! (){returni;} intoperator~(){return! *(A*)this;} }; voidmain() { Bb(1,2); cout< b< cout< (A)b< cout<<~b< cin.get(); } 例13: C#语言示例 usingSystem; classA { protectedinti; publicA(intx){i=x;} publicintlist(){returni;} }; classB: A { protectednewinti;//注意成员覆盖的new书写语法 publicB(intx,inty): base(y){i=x;} publicnewintlist(){returnbase.i;}//注意成员覆盖的new书写语法 staticvoidMain() { Cc=newC(1,2,3); Console.Write(c.list()); } }; classC: B { protectednewinti;//注意成员覆盖的书写语法 publicC(intx,inty,intz): base(y,z){i=x;} publicnewintlist(){returni;}//注意成员覆盖的书写语法 }; C#语言中出现成员覆盖时,在派生类中定义同名成员是否使用new关键字按以下原则确定: •数据成员同名; •函数成员同名且代码不一致; C#语言中的派生类对象成员函数若要访问上一个基类对象成员,则需要在其成员名之前前缀base关键字。 但若上一个基类对象的成员访问权被禁止,则继续向前面一级的基类对象成员定位,直至出错。 ⑥多重派生的实现 C++语言是目前唯一支持多重派生技术面向对象语言。 其语法声明格式为: public类名i,public类名j,… class类名1: protected类名x,protected类名y,…{成员声明}; private类名k,private类名m,… 同单一派生一样,多重派生也要遵守上述规则或约定。 例14: #include usingnamespacestd; classA { inti; public: A(intx): i(x){} voidoperator! (){cout< }; classB { protected: inti; public: B(intx): i(x){} }; classC: publicA,publicB { inti; public: C(intx,inty,intz): i(x),B(y),A(z){} voidoperator! (){cout< : i< *(A*)this;} }; voidmain() { Cc(1,2,3); ! c; } ⑦派生类对象与基类的对象成员之间的互相提取 对于C++语言,仅在以public方式继承的情况下才能进行这种对象成员间相互提取。 可能存在的两种情况: ·已知独立一个基类对象而要提取其全部成员赋予另一个派生类对象中的基类对象; ·已知一个派生类对象而要提取其内含的基类对象的全部成员赋予另一个独立的基类对象; 对于C#语言,只能实现上述两种状况的后者。 对于前者的编码,即使能勉强通过编译,也会导致在系统运行中发生意外的存储器访问错误。 例15: #include usingnamespacestd; classA { inti; public: A(intx): i(x){} voidIncrease_One(){i++;} voidoperator! (){cout<<"I="< }; classB: publicA { intl; public: B(): A(0){l=0;Increase_One();} voidoperator! (){! *(A*)this;cout<<"L="< }; voidmain() {//最后的显示结果为: Aa (1);//I=1,L=6618680 B*b0=(B*)&a,&b1=(B&)a;//I=1,L=6618680 ! *b0;! b1;//其中的L值是不确定的 cin.get(); } 这样提取得到的派生类对象内的本类作用域实际上根本不存在。 因而要谨慎应用。 例16: C++语言示例 #include usingnamespacestd; classA { inti; public: A(intx): i(x){} voidoperator! (){cout<<"I="< voidIncrease_One(){i++;} }; classB: publicA { intl; public: B(intn=0): A(0),l(n){Increase_One();} voidoperator! (){! *(A*)this;cout<<"L="< }; voidmain() { Bb1(5);//最后的显示结果为: Aa1=b1;//I=1 A*a2=newB(4);//I=1 A&a3=b1,*a4=&b1;//I=1 ! a1;! *a2;! a3;! *a4;//I=1 } 例17: C#语言示例 usingSystem; classA { protectedinti; publicA(intx){i=x;} publicintdsp(){returni;} }; classB: A { protectednewinti; publicB(intx,inty): base(y){i=x;} publicnewintdsp(){returnbase.i;} staticvoidMain() { Aa=newA (1); Bb=newB(1,3); a=b; Console.Write(a.dsp());//显示3 } }; ⒊多态(Polymorphism)与抽象类(AbstractClasses) 1虚拟函数(virtualfunction) 鉴于基类是反映一个类家族全貌的Supclass,在其派生出的各个派生类对象中必然存在基类的成员(函数)。 若能使用基类的指针(或引用)指向其某个派生类对象,便可以利用对象当前作用域的限制实现“以不变应万变”或者“以变应变”的设想了。 C++和C#语言将实现此种设想的技术方法叫做虚拟函数。 推论: 虚拟函数应当是基类成员声明的一种特别的语法形式。 虚拟函数的声明格式为: virtual类型函数声明体; 使用虚拟函数的具体语法要领如下: ·虚拟成员函数必须在基类中予以声明; ·虚拟成员函数可以在派生类中被覆盖(C#语言中必须在派生类的同名成员函数声明使用override关键字); ·引用派生类中重写的虚拟成员函数只能通过基类的指针或引用实现; ·若派生类中没有再定义基类中已声明为虚拟成员的函数,则指向该类的对象的指针或引用名调用该虚拟成员函数时总是调用距离其最靠近的一个基类中的虚拟成员函数。 ·构造函数和静态成员函数(即类方法)不得声明为虚拟函数; ·C#语言可以某个产生了覆盖成员函数的派生类中使用sealed关键字对该成员函数进行密封,阻断继续被重写的可能(这与C#语言没有派生方式有关); 例18: C++语言示例 #include usingnamespacestd; classA { protected: inti; public: A(intx): i(x){} virtualvoidoperator! (){cout<<"i="< }; classB: publicA { intl; public: B(intn=0): A(0),l(n){i++;} voidoperator! (){cout<<"i="< }; voidmain() { Bb(5); Aa (2);//最后的显示结果为: A*ab=&a;! *ab;//i=2 ab=&b;! *ab;//i=1,l=5 A&ba=b;! ba;//i=1,l=5 } 例19: C#语言示例 usingSystem; classA { protectedinti; publicA(intx){i=x;} publicvirtualintdsp(
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- oolecture9