派生类到基类的转换 和基类到派生类的转换
一、 基類與派生類的轉換
????3種繼承方式(公用、保護、私有繼承)中,公用派生類才是基類真正的子類型,它完整地繼承了基類的功能。
????不同類型數據之間在一定條件下可以進行類型的轉換。基類與派生類對象之間是否也有賦值兼容的關系,可否進行類型間的轉換?回答是可以的。基類與派生類對象之間有賦值兼容關系,由于派生類中包含從基類繼承的成員,因此可以將派生類的值賦給基類對象,在用到基類對象的時候可以用其子類對象代替?。
注意:有的數據類型是不可轉換的;有的轉換是不可逆的。
1、派生類對象可以向基類對象賦值。
可以用子類(即公用派生類)對象對其基類對象賦值。
如:?
??? A al;?//定義基類A對象al?
??? B bl;?//定義類A的公用派生類B的對象bl?
??? a1=b1;?//用派生類B對象bl對基類對象al賦值
實際上,所謂賦值只是對數據成員賦值,對成員函數不存在賦值問題。
注意:
????1、賦值后不能企圖通過對象a1去訪問派生類對象bl的成員,因為bl的成員與al的成員是不同的。假設ase是派生類B中增加的公用數據成員,分析下面的用法:
a1.age=23;//錯誤,al中不包含派生類中增加的成員?
b1.age=21;//正確,b1中包含派生類中增加的成員
????2、子類型關系是單向的、不可逆的。B是A的子類型,不能說A是B的子類型。只能用子類對象對其基類對象賦值,而不能用基類對象對其子類對象賦值,理由是顯然的,因為基類對象不包含派生類的成員,無法對派生類的成員賦值。同理,同一基類的不同派生類對象之間也不能賦值。
2、派生類對象可以替代基類對象向基類對象的引用進行賦值或初始化?。
如已定義了基類A對象a1,可以定義a1的引用:
A al;?//定義基類A對象al?
B bl;?//定義公用派生類B對象bl?
A&r=al;//定義基類A對象的引用變量r,并用a1對其初始化
????引用r是al的別名,r和a1共享同一段存儲單元。可以用子類對象初始化引用r,將上面最后一行改為:
????A&r=bl;//定義基類A對象的引用變量r,并用派生類B對象b1對其初始化或者保留上面第3行“A&r=al;”,而對r重新賦值:?
????r=bl;?//用派生類B對象bl對a1的引用變量r賦值
注意?:此時r并不是bl的別名,也不與bl共享同一段存儲單元。它只是b1中基類部分的別名,r與bl中基類部分共享同一段存儲單元,r與b1具有相同的起始地址。
3、如果函數的參數是基類對象或基類對象的引用,相應的實參可以用子類對象。
如有一函數fun:
????void fun(A&r)???????????//形參是類A的對象的引用?
???????{?cout<<r.num<<endl;}//輸出該引用所代表的對象的數據成員num
????函數的形參是類A的對象的引用變量,本來實參應該為A類的對象。由于子類對象與派生類對象賦值兼容,派生類對象能自動轉換類型,在調用fun函數時可以用派生類B的對象bl作實參: fun(b1);
輸出類B的對象bl的基類數據成員num的值。
???在fun函數中只能輸出派生類中基類成員的值?。
4、派生類對象的地址可以賦給指向基類對象的指針變量,也就是說,指向基類對象的指針變量也可以指向派生類對象。
例10?定義一個基類Student(學生),再定義Student類的公用派生類Graduate(研究生),用指向基類對象的指針輸出數據。
本例主要是說明用指向基類對象的指針指向派生類對象,為了減少程序長度,在每個類中只設很少成員。學生類只設num(學號),name(名字)和score(成績)3個數據成員,Graduate類只增加一個數據成員pay(工資)?:
#include <string>
using namespace std;
class Student??????????//聲明Student類?
????{?public:
???????Student(int,string,float);?//聲明構造函數?
????????void display();?????//聲明輸出函數?
???????private:
????????int num;
????????string name;
????????float score; };
Student::Student(int n,string nam,float s)//定義構造函數?
????{?num=n;
????????name=nam;
????????score=s; }
void Student::display()????//定義輸出函數?
???{?cout<<endl<<"num:"<<num<<endl;
????cout<<"name:"<<name<<endl;
????cout<<"score:"<<score<<endl; }
class Graduate:public Student?//聲明公用派生類Graduale?
????{?public:
????????Graduate(int,string,float,float);//聲明構造函數
????????void display();?????//聲明輸出函數?
???????private:
???????float pay; };???????//工資?
void Graduate::display()????//定義輸山函數?
???{?Student::display();????//調用Student類的display函數?
????cout<<"pay="<<pay<<endl; }
Graduate::Graduate(int n,string nam,float s,float p):Student(n,nam,s),pay(p){}
??????? //定義構造函數
int main()
{?Student stud1(1001,"Li",87.5);?????????//定義Student類對象stud1?
?? Graduate grad1(2001,"Wang",98.5,563.5);//定義Graduate類對象grad1?
???Student *pt=&stud1;???????//定義指向Student類對象的指針并指向studl?
????pt->display();???????????//調用studl.display函數?
????pt=&grad1;???????????????//指針指向gradl?
????pt->display();???????????//調用gradl.display函數?
????return 0; }
程序的輸出結果:?
????????num:1001
????????name:Li
????????score:87.5
????????num:2001
????????nume:wang
????????score:98.5
為什么沒有輸出pay的值?
??? 通過本例可以看到:?用 指向基類對象的指針變量指向子類對象是合法的、安全的,不會出現編譯上的錯誤。但在應用上卻不能完全滿足人們的希望,人們有時希望通過使用基類指針能夠調 用基類和子類對象的成員。如果能做到這點,程序人員會感到方便。在下一章就要解決這個問題。辦法是使用虛函數和多態性。
總結
以上是生活随笔為你收集整理的派生类到基类的转换 和基类到派生类的转换的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 吃透Java中的动态代理
- 下一篇: Java转型(向上或向下转型)