一融撞、類的繼承與類的派生
繼承的概念
通過已有的類建立新類的過程,叫做類的派生
粗蔚。
原來的類稱為基類尝偎,也稱為父類或一般類;新類稱為派生類鹏控,也稱為子類或特殊類致扯。
派生類的定義與大小
派生類的定義
在C++語言中,從基類派生派生類的格式
class 派生類名 : 繼承方式說明符 基類名
{
類體
};
繼承方式說明符指明如何控制基類成員在派生類中的訪問屬性当辐,通常有public抖僵、private和protected 3中方式。
例5-1 基類與派生類的定義
class BaseClass //基類
{
int v1,v2;
};
class DerivedClass:public BaseClass //派生類
{
int v3;
};
空類也可以作為基類缘揪。
程序5-1 派生類該百年基類成員的訪問權(quán)限
#include <iostream>
using namespace std;
class BaseClass
{
public:
int v1,v2;
BaseClass():v1(1),v2(1){}
int temp1(){}
};
class DerivedClass:public BaseClass
{
int v1;
int temp1(){}
public:
DerivedClass():v1(10){}
void printv()
{
cout<<"v1="<<v1<<endl;
cout<<"Base.v1="<<BaseClass::v1<<endl;
}
};
int main()
{
BaseClass bc;
DerivedClass dc;
dc.printv();
return 0;
}
v1=10
Base.v1=1
類的大小
派生類大小占用的存儲空間大小耍群,等于基類成員變量占用的存儲空間大小加上派生類大小自身成員變量占用的存儲空間大小义桂。可以使用sizeof()函數(shù)計(jì)算大小占用的字節(jié)數(shù)蹈垢。
為類大小分配空間時慷吊,遵循字節(jié)對齊的原則,空類的大小是1曹抬,這是一種特殊情況溉瓶。
對象占用的存儲空間包含對象中各成員變量占用的存儲空間。對象的大小與普通成員變量有關(guān),與成員函數(shù)和類中的靜態(tài)成員變量無關(guān)沐祷,即普通成員函數(shù)嚷闭、靜態(tài)成員函數(shù)、靜態(tài)成員變量赖临、靜態(tài)常量成員變量等均對類對象的大小沒有影響胞锰。
程序5-2 基類與子類占用空間及字節(jié)對齊
#include <iostream>
using namespace std;
class BaseClass
{
int v1,v2;
char v4;
public:
int temp1(){}
};
class DerivedClass:public BaseClass
{
int v3;
int *p;
public:
int temp(){}
};
int main()
{
cout<<"Base="<<sizeof(BaseClass)<<endl;
cout<<"Derived="<<sizeof(DerivedClass)<<endl;
return 0;
}
Base=12
Derived=24
繼承關(guān)系的特殊性
如果基類有友元類或友元函數(shù),則其派生類不會因繼承關(guān)系而也有此友元類或友元函數(shù)兢榨。
如果基類是某類的友元嗅榕,則這種友元關(guān)系是被繼承的。即被派生類繼承過來的成員函數(shù)吵聪。
如果原來是基類的友元函數(shù)凌那,那么它作為派生類的成員函數(shù)仍然是某類的友元函數(shù)。
基類的友元不一定是派生類的友元吟逝;基類的成員函數(shù)是某類的友元函數(shù)帽蝶,則其作為派生類繼承的成員函數(shù)仍是某類的友元函數(shù)。
程序5-3 派生類繼承了友元函數(shù)
#include <iostream>
using namespace std;
class another; //前向引用聲明
class Base //基類
{
private:
float x;
public:
void print(const another &K);
};
class Derived:public Base //派生類
{
private:
float y;
};
class another
{
private:
int aaa;
public:
another()
{
aaa = 100;
}
friend void Base::print(const another &K);
};
void Base::print(const another &K)
{
cout<<"Base:"<<K.aaa<<endl;
}
int main()
{
Base a;
Derived d;
another ano;
a.print(ano);
d.print(ano);
return 0;
}
Base:100
Base:100
如果派生類Derived中重寫了print()函數(shù)块攒,若還想在函數(shù)中訪問another的私有成員励稳,則必須將類Derived的print()函數(shù)也聲明為another的友元。
程序5-4 派生關(guān)系中的靜態(tài)成員
#include <iostream>
using namespace std;
class Base
{
private:
float x;
public:
static int staV;
Base()
{
staV++;
}
};
int Base::staV = 0;
class Derived:public Base
{
private:
float y;
public:
Derived()
{
staV++;
}
};
int main()
{
Base a;
cout<<a.staV<<endl;
Derived d;
cout<<d.staV<<endl;
return 0;
}
1
3
有繼承關(guān)系的類之間的訪問
在類的派生層次結(jié)構(gòu)中囱井,基類的成員和派生類新增的成員都具有類作用域驹尼。二者的作用范圍不同,是相互包含的兩個層庞呕,派生類在內(nèi)層新翎,基類在外層。
程序5-5 訪問基類和派生類成員的方式
#include <iostream>
using namespace std;
class CB
{
public:
int a;
CB(int x)
{
a = x;
}
void showa()
{
cout<<"Class CB--a="<<a<<endl;
}
};
class CD:public CB
{
public:
int a;
CD(int x,int y):CB(x)
{
a = y;
}
void showa()
{
cout<<"Class CD--a="<<a<<endl;
}
void print2a()
{
cout<<"a="<<a<<endl;
cout<<"CB:a="<<CB::a<<endl;
}
};
int main()
{
CB CBobj(12);
CBobj.showa();
CD CDobj(48,999);
CDobj.showa();
CDobj.CB::showa();
cout<<"CDobj.a="<<CDobj.a<<endl;
cout<<"CDobj.CB::a="<<CDobj.CB::a<<endl;
}
Class CB--a=12
Class CD--a=999
Class CB--a=48
CDobj.a=999
CDobj.CB::a=48
程序5-6 類之間的訪問示例
#include <iostream>
#include <string>
using namespace std;
class CStudent
{
private:
string name; //姓名
string id; //學(xué)號
char gender; //性別住练,'F'代表女生地啰,'M'代表男生
int age; //年齡
public:
void PrintInfo();
void SetInfo(const string &,const string &,int,char);
void SetName(string);
string GetName();
void SetId(string);
string GetId();
};
void CStudent::PrintInfo()
{
cout<<"姓名:\t"<<name<<endl;
cout<<"學(xué)號:\t"<<id<<endl;
cout<<"年齡:\t"<<age<<endl;
cout<<"性別:\t"<<gender<<endl;
}
void CStudent::SetInfo(const string & name_,const string & id_,int age_,char gender_)
{
name = name_;
id = id_;
age = age_;
gender = gender_;
}
void CStudent::SetName(string name)
{
this->name = name;
}
string CStudent::GetName()
{
return name;
}
void CStudent::SetId(string id)
{
this->id = id;
}
string CStudent::GetId(){
return id;
}
class CUndergraduateStudent:public CStudent //本科生類,繼承于類CStudent
{
private:
string department; //學(xué)生所屬的系名
public:
void PrintInfo();
void SetInfo(const string &,const string &,int,char,const string &);
};
void CUndergraduateStudent::PrintInfo()
{
CStudent::PrintInfo(); //調(diào)用基類的公有PrintInfo函數(shù)
cout<<"院系:\t"<<department<<endl<<endl; //訪問的是本派生類的成員變量
}
void CUndergraduateStudent::SetInfo(const string & name_,const string & id_,int age_,char gender_,const string & department_)
{
CStudent::SetInfo(name_,id_,age_,gender_); //調(diào)用基類的公有SetInfo函數(shù)
department = department_;
}
class CGraduatedStudent:public CStudent //研究生類,繼承于類CStudent
{
private:
string department;
string advisor; //導(dǎo)師
public:
void PrintInfo();
void SetInfo(const string & name_,const string & id_,int age_,char gender_,const string & department_,const string & advisor_);
};
void CGraduatedStudent::PrintInfo()
{
CStudent::PrintInfo();
cout<<"院系:\t"<<department<<endl;
cout<<"導(dǎo)師:\t"<<advisor<<endl<<endl;
}
void CGraduatedStudent::SetInfo(const string & name_,const string & id_,int age_,char gender_,const string & department_,const string & advisor_)
{
CStudent::SetInfo(name_,id_,age_,gender_);
department = department_;
advisor = advisor_;
}
int main()
{
CStudent s1;
CUndergraduateStudent s2;
CGraduatedStudent s3;
s2.SetInfo("小張","2018-6-2-4",19,'M',"數(shù)學(xué)系");
s3.SetInfo("小李","M2017-9",23,'F',"計(jì)算機(jī)學(xué)院","孟教授");
s2.PrintInfo();
s3.PrintInfo();
// cout<<s2.name<<endl;
// s2.name = "張一";
cout<<s2.GetName()<<endl;
s2.SetName("張一");
s2.PrintInfo();
cout<<s2.GetName()<<","<<s2.GetId()<<endl;
return 0;
}
姓名: 小張
學(xué)號: 2018-6-2-4
年齡: 19
性別: M
院系: 數(shù)學(xué)系
姓名: 小李
學(xué)號: M2017-9
年齡: 23
性別: F
院系: 計(jì)算機(jī)學(xué)院
導(dǎo)師: 孟教授
小張
姓名: 張一
學(xué)號: 2018-6-2-4
年齡: 19
性別: M
院系: 數(shù)學(xué)系
張一,2018-6-2-4
程序5-7 類之間的訪問
假設(shè)公司雇員分為雇員(employee)讲逛、經(jīng)理(manager)髓绽、工程師(engineer)和高級主管(director)。各類的屬性如下:
employee(雇員)類:姓名妆绞、年齡顺呕、工資;
manager(經(jīng)理)類:姓名、年齡括饶、工資株茶、行政級別;
engineer(工程師)類:姓名、年齡图焰、工資启盛、專業(yè)、學(xué)位:
director(高級主管)類:姓名技羔、年齡僵闯、工資、行政級別藤滥、職務(wù)鳖粟。
將類employee 設(shè)計(jì)為基類,含有成員變量:姓名拙绊、年齡和工資向图。類manager 和類 engineer 是類employee的派生類,類director是類manager的派生類标沪。
#include <iostream>
#include <string>
using namespace std;
class employee //類employee將作為其他幾個類的基類
{
short age;
float salary;
protected:
string name;
public:
employee(short ag,float sa,string na)
{
age = ag;
salary = sa;
name = na;
};
void print()
{
cout<<"\n"<<name<<":\t";
cout<<age<<":\t";
cout<<salary;
}
~employee(){}
};
class manager:public employee //派生類
{
int level;
public:
manager(short ag,float sa,string na,int lev):employee(ag,sa,na) //對基類初始化
{
level = lev;
}
void print()
{
employee::print();
cout<<"\tlevel:"<<level;
}
};
class engineer:public employee
{
char speciality,adegree;
public:
engineer(short ag,float sa,string na,char spe,char ade):employee(ag,sa,na)
{
speciality = spe;
adegree = ade;
}
void print()
{
employee::print();
cout<<"\tspeciality:"<<speciality;
cout<<"\tadegree:"<<adegree;
}
};
enum ptitle {PS,GM,VPS,VGM};
class director:public manager
{
ptitle post;
public:
director(short ag,float sa,string na,int le,ptitle po):manager(ag,sa,na,le)
{
post = po;
}
void print()
{
manager::print();
cout<<"\tpost:"<<post<<endl;
}
};
int main()
{
employee emp1(23,610.5,"wang"),emp2(27,824.75,"li");
manager man1(32,812.45,"zhang",11),man2(34,1200.5,"chen",7);
engineer eng(26,1420.10,"sun",'E','M');
director dir(38,1800.2,"liu",2,VPS);
emp1.print();
emp2.print();
man1.print();
man2.employee::print();
eng.print();
dir.print();
}
wang: 23: 610.5
li: 27: 824.75
zhang: 32: 812.45 level:11
chen: 34: 1200.5
sun: 26: 1420.1 speciality:E adegree:M
liu: 38: 1800.2 level:2 post:2
protected訪問范圍說明符
基類中的保護(hù)成員可以在派生類的成員函數(shù)中被訪問榄攀。
程序5-8 基類中的成員是私有成員時的訪問方式
#include <iostream>
using namespace std;
class BaseClass
{
int v1,v2; //私有成員變量
public:
void SetValue(int m,int n)
{
v1 = m;
v2 = n;
}
void PrintValue();
};
void BaseClass::PrintValue()
{
cout<<"v1="<<v1<<"\tv2="<<v2;
}
class DerivedClass:public BaseClass
{
int v3;
public:
void SetValue(int m,int n,int k)
{
BaseClass::SetValue(m,n);
v3 = k;
}
void PrintValue();
};
void DerivedClass::PrintValue()
{
cout<<endl;
BaseClass::PrintValue();
cout<<"\tv3="<<v3<<endl;
}
int main()
{
BaseClass baseCla;
DerivedClass derivedCla;
cout<<"初始時的隨機(jī)值: "<<endl;
baseCla.PrintValue();
derivedCla.PrintValue();
cout<<"修改基類中的值后: "<<endl;
baseCla.SetValue(10,20);
baseCla.PrintValue();
derivedCla.PrintValue();
cout<<"從派生類修改從基類繼承的值及本類的值: "<<endl;
derivedCla.SetValue(100,200,300);
baseCla.PrintValue();
derivedCla.PrintValue();
return 0;
}
初始時的隨機(jī)值:
v1=0 v2=0
v1=0 v2=0 v3=19
修改基類中的值后:
v1=10 v2=20
v1=0 v2=0 v3=19
從派生類修改從基類繼承的值及本類的值:
v1=10 v2=20
v1=100 v2=200 v3=300
程序5-9 基類中保護(hù)成員的訪問方式
#include <iostream>
using namespace std;
class BaseClass
{
protected:
int v1,v2;
public:
void SetValue(int m,int n)
{
v1 = m;
v2 = n;
}
void PrintValue();
};
void BaseClass::PrintValue()
{
cout<<"v1="<<v1<<"\tv2="<<v2;
}
class DerivedClass:public BaseClass
{
int v3;
public:
void SetValue(int m,int n,int k)
{
v1 = m;
v2 = n;
v3 = k;
}
void SetValue(int m,int n)
{
v1 = m;
v2 =n;
}
void PrintValue();
};
void DerivedClass::PrintValue()
{
cout<<endl;
BaseClass::PrintValue();
cout<<"\tv3="<<v3<<endl;
}
int main()
{
BaseClass baseCla;
DerivedClass derivedCla;
cout<<"初始時的隨機(jī)值: "<<endl;
baseCla.PrintValue();
derivedCla.PrintValue();
cout<<"修改基類中的值后: "<<endl;
baseCla.SetValue(10,20);
baseCla.PrintValue();
derivedCla.PrintValue();
cout<<"從派生類修改從基類繼承的值及本類的值: "<<endl;
derivedCla.SetValue(100,200,300);
baseCla.PrintValue();
derivedCla.PrintValue();
return 0;
}
初始時的隨機(jī)值:
v1=0 v2=0
v1=0 v2=0 v3=19
修改基類中的值后:
v1=10 v2=20
v1=0 v2=0 v3=19
從派生類修改從基類繼承的值及本類的值:
v1=10 v2=20
v1=100 v2=200 v3=300
多重繼承
C++允許從多個類派生一個類,即一個派生類可以同時有多個基類金句。這稱為多重繼承檩赢。
從一個基類派生一個派生類的情況,稱為單繼承或單重繼承违寞。
一個類從多個基類派生的格式
class 派生類名 : 繼承方式說明符 基類名1贞瞒,繼承方式說明符 基類名2,...坞靶,繼承方式說明符 基類名n
{
類體
};
程序5-10 多重繼承下的訪問方式
#include <iostream>
using namespace std;
class CB1
{
public:
int a; //重名
CB1(int x)
{
a = x;
}
void showa() //重名
{
cout<<"Class CB1==>a="<<a<<endl;
}
};
class CB2
{
public:
int a; //重名
CB2(int x)
{
a = x;
}
void showa() //重名
{
cout<<"Class CB2==>a="<<a<<endl;
}
};
class CD : public CB1,public CB2 //多重繼承憔狞,兩個基類
{
public:
int a; //與兩個基類成員變量a重名
CD(int x,int y,int z):CB1(x),CB2(y)
{
a = z;
}
void showa() //與兩個基類成員函數(shù)showa()重名
{
cout<<"Class CD==>a="<<a<<endl;
}
void print3a()
{
cout<<"a="<<a<<endl;
cout<<"CB1::a="<<CB1::a<<endl;
cout<<"CB2::a="<<CB2::a<<endl;
}
};
int main()
{
CB1 CB1obj(11);
CB1obj.showa();
CD CDobj(101,202,909);
CDobj.showa();
CDobj.CB1::showa();
cout<<"CDobj.a="<<CDobj.a<<endl;
cout<<"CDobj.CB2::a="<<CDobj.CB2::a<<endl;
}
Class CB1==>a=11
Class CD==>a=909
Class CB1==>a=101
CDobj.a=909
CDobj.CB2::a=202
多重繼承方式下,為避免二義性彰阴,成員變量的訪問方式如下
程序5-11 多重繼承
#include <iostream>
using namespace std;
class BaseClass1
{
public:
int v1,v2;
BaseClass1();
BaseClass1(int,int);
~BaseClass1();
};
BaseClass1::BaseClass1()
{
cout<<"BaseClass1 無參構(gòu)造函數(shù)"<<endl;
}
BaseClass1::BaseClass1(int m,int n):v1(m),v2(n)
{
cout<<"BaseClass1 帶2個參數(shù)構(gòu)造函數(shù)"<<endl;
}
BaseClass1::~BaseClass1()
{
cout<<"BaseClass1 析構(gòu)函數(shù)"<<endl;
}
class BaseClass2
{
public:
int v1,v4;
BaseClass2();
BaseClass2(int,int);
~BaseClass2();
};
BaseClass2::BaseClass2()
{
cout<<"BaseClass2 無參構(gòu)造函數(shù)"<<endl;
}
BaseClass2::BaseClass2(int m,int n):v1(m),v4(n)
{
cout<<"BaseClass2 帶2個參數(shù)構(gòu)造函數(shù)"<<endl;
}
BaseClass2::~BaseClass2()
{
cout<<"BaseClass2 析構(gòu)函數(shù)"<<endl;
}
class DerivedClass:public BaseClass1,public BaseClass2
{
public:
int v3;
public:
DerivedClass();
DerivedClass(int);
DerivedClass(int,int,int,int);
~DerivedClass();
};
DerivedClass::DerivedClass()
{
cout<<"DerivedClass 無參構(gòu)造函數(shù)"<<endl;
}
DerivedClass::DerivedClass(int k):v3(k)
{
cout<<"DerivedClass 帶1個參數(shù)的構(gòu)造函數(shù)"<<endl;
}
DerivedClass::DerivedClass(int m,int n,int k,int t):BaseClass1(m,n),BaseClass2(m,t),v3(k)
{
cout<<"DerivedClass 帶4個參數(shù)的構(gòu)造函數(shù)"<<endl;
}
DerivedClass::~DerivedClass()
{
cout<<"DerivedClass 析構(gòu)函數(shù)"<<endl;
}
int main()
{
cout<<"帶參數(shù)對象的創(chuàng)建"<<endl;
DerivedClass derivedCla1(1000,2000,3000,4000);
cout<<"v1="<<derivedCla1.BaseClass1::v1<<endl;
cout<<"v2="<<derivedCla1.v2<<endl;
cout<<"v1="<<derivedCla1.BaseClass2::v1<<endl;
cout<<"v4="<<derivedCla1.v4<<endl;
cout<<"v3="<<derivedCla1.v3<<endl;
return 0;
}
帶參數(shù)對象的創(chuàng)建
BaseClass1 帶2個參數(shù)構(gòu)造函數(shù)
BaseClass2 帶2個參數(shù)構(gòu)造函數(shù)
DerivedClass 帶4個參數(shù)的構(gòu)造函數(shù)
v1=1000
v2=2000
v1=1000
v4=4000
v3=3000
DerivedClass 析構(gòu)函數(shù)
BaseClass2 析構(gòu)函數(shù)
BaseClass1 析構(gòu)函數(shù)
二瘾敢、 訪問控制
公有繼承
當(dāng)類的繼承方式為公有繼承時,基類的公有成員在派生類中直接訪問尿这,在基類與派生類外直接訪問;基類的保護(hù)成員在派生類中直接訪問,在基類與派生類外調(diào)用公有函數(shù)訪問;基類的私有成員在派生類中調(diào)用公有函數(shù)訪問,在基類與派生類外調(diào)用公有函數(shù)訪問簇抵。
當(dāng)類的繼承方式為公有繼承時,派生類中定義的公有成員在派生類中直接訪問.在基類與派生類外直接訪問;派生類中定義的保護(hù)成員在派生類中直接訪問射众,在基類與派生類外調(diào)用公有函數(shù)訪問;派生類中定義的私有成員在派生類中直接訪問,在基類與派生類外調(diào)用公有函數(shù)訪問碟摆。
表5-1 公有繼承的訪問控制
各成員 | 派生類中 | 基類與派生類外 |
---|---|---|
基類的公有成員 | 直接訪問 | 直接訪問 |
基類的保護(hù)成員 | 直接訪問 | 調(diào)用公有函數(shù)訪問 |
基類的私有成員 | 調(diào)用公有函數(shù)訪問 | 調(diào)用公有函數(shù)訪問 |
從基類繼承的公有成員 | 直接訪問 | 直接訪問 |
從基類繼承的保護(hù)成員 | 直接訪問 | 調(diào)用公有函數(shù)訪問 |
從基類繼承的私有成員 | 調(diào)用公有函數(shù)訪問 | 調(diào)用公有函數(shù)訪問 |
派生類中定義的公有成員 | 直接訪問 | 直接訪問 |
派生類中定義的保護(hù)成員 | 直接訪問 | 調(diào)用公有函數(shù)訪問 |
派生類中定義的私有成員 | 直接訪問 | 調(diào)用公有函數(shù)訪問 |
程序5-12 公有繼承訪問控制示例
#include <iostream>
#include <string>
using namespace std;
class Base
{
public:
int vBPub;
protected:
int vBPro;
private:
int vBPri;
public:
Base()
{
vBPub = 10;
vBPro = 20;
vBPri = 30;
};
void SetPriValue(int);
void SetProValue(int,int);
int GetPriValue();
int GetProValue();
};
void Base::SetPriValue(int k)
{
vBPri = k;
}
void Base::SetProValue(int m,int n)
{
vBPro = m;
vBPri = n;
}
int Base::GetPriValue()
{
return vBPri;
}
int Base::GetProValue()
{
return vBPro;
}
class Derived:public Base
{
public:
int vDPub,vBPub;
protected:
int vDPro;
private:
int vDPri;
public:
Derived()
{
vDPub = 100;
vDPro = 200;
vDPri = 300;
vBPub = 15;
};
void SetPriValue(int);
void SetProValue(int,int);
int GetPriValue();
int GetProValue();
void PrintValue();
};
void Derived::SetPriValue(int k)
{
vDPri = k;
}
void Derived::SetProValue(int m,int n)
{
vDPro = m;
vDPri = n;
Base::vBPro = 2*m;
// Base::vBPri = 2*n; //不可以直接訪問從基類繼承的私有成員變量
}
int Derived::GetPriValue()
{
return vDPri;
}
int Derived::GetProValue()
{
return vDPro;
}
void Derived::PrintValue()
{
cout<<"在派生類中訪問基類"<<endl;
cout<<"基類公有變量: "<<vBPub<<endl; //派生類可以訪問基類的公有成員變量
cout<<"基類保護(hù)變量: "<<vBPro<<endl; //派生類可以訪問基類的保護(hù)成員變量
// cout<<Base::vBPri<<endl; //不能直接訪問基類的私有變量
cout<<"基類私有變量: "<<Base::GetPriValue()<<endl; //通過函數(shù)訪問
cout<<"在派生類中訪問派生類"<<endl;
cout<<"派生類公有變量: "<<vDPub<<endl;
cout<<"派生類保護(hù)變量: "<<vDPro<<endl;
cout<<"派生類私有變量: "<<vDPri<<endl;
cout<<"從基類繼承的公有變量: "<<Base::vBPub<<endl;
cout<<"從基類繼承的保護(hù)變量: "<<Base::vBPro<<endl;
// cout<<"從基類繼承的私有變量: "<<Base::vBPri<<endl; //不可以直接訪問
}
int main()
{
Base bObj;
Derived dObj;
cout<<"在主函數(shù)中訪問基類"<<endl;
cout<<"公有成員: "<<bObj.vBPub<<endl;
// cout<<"保護(hù)成員: "<<bObj.vBPro<<endl; //不能直接訪問保護(hù)成員變量
cout<<"保護(hù)成員: "<<bObj.GetProValue()<<endl; //通過函數(shù)訪問
cout<<"私有成員: "<<bObj.GetPriValue()<<endl;
cout<<"在主函數(shù)中訪問派生類"<<endl;
cout<<"公有成員: "<<dObj.vDPub<<endl;
// cout<<"保護(hù)成員: "<<dObj.vDpro<<endl; //不能直接訪問保護(hù)成員變量
cout<<"保護(hù)成員: "<<dObj.GetProValue()<<endl;
cout<<"基類 保護(hù)成員: "<<dObj.Base::GetProValue()<<endl;
cout<<"私有成員: "<<dObj.GetPriValue()<<endl;
cout<<"dObj.vBPub="<<dObj.vBPub<<endl;
cout<<"dObj.Base::vBpub="<<dObj.Base::vBPub<<endl;
dObj.PrintValue();
return 0;
}
在主函數(shù)中訪問基類
公有成員: 10
保護(hù)成員: 20
私有成員: 30
在主函數(shù)中訪問派生類
公有成員: 100
保護(hù)成員: 200
基類 保護(hù)成員: 20
私有成員: 300
dObj.vBPub=15
dObj.Base::vBpub=10
在派生類中訪問基類
基類公有變量: 15
基類保護(hù)變量: 20
基類私有變量: 30
在派生類中訪問派生類
派生類公有變量: 100
派生類保護(hù)變量: 200
派生類私有變量: 300
從基類繼承的公有變量: 10
從基類繼承的保護(hù)變量: 20
類型兼容規(guī)則
類型兼容規(guī)則是指在需要基類對象的任何地方,都可以使用公有派生類的對象來替代叨橱,也稱為賦值兼容規(guī)則典蜕。
在公有派生的情況下断盛,又以下3條類型兼容規(guī)則。
- 派生類的對象可以賦值給基類對象愉舔。
- 派生類對象可以用來初始化基類引用钢猛。
- 派生類對象的地址可以賦值給基類指針。
程序5-13 類型兼容規(guī)則的使用
#include <iostream>
using namespace std;
class A
{
int an;
public:
A(){}
A(int n)
{
an = n;
}
};
class B:public A
{
int bn;
public:
B(int n):A(2*n)
{
bn = n;
}
};
int main()
{
A a(10);
B b(20);
a = b;
return 0;
}
程序5-14 驗(yàn)證使用類型兼容規(guī)則的輸出結(jié)果
#include <iostream>
using namespace std;
class A
{
int an;
public:
A(){}
A(int n)
{
an = n;
}
void print()
{
cout<<"A的對象:";
cout<<"an:"<<an;
}
void print(int k)
{
cout<<"an:"<<an;
}
};
class B:public A
{
int bn;
public:
B(int n):A(2*n)
{
bn = n;
}
void print()
{
cout<<"\nB的對象:";
A::print(1);
cout<<",bn="<<bn<<endl;
}
};
int main()
{
A a(10);
B b(20);
a.print();
b.print();
a = b;
a.print();
b.print();
return 0;
}
A的對象:an:10
B的對象:an:40,bn=20
A的對象:an:40
B的對象:an:40,bn=20
私有繼承
當(dāng)類的繼承方式為私有繼承時,基類的公有成員在第一級派生類中可以直接訪問轩缤,在第二級派生類中不可訪問,在基類與派生類外不可訪問;基類的保護(hù)成員在第一級派生類中可以直接訪問,在第二級派生類中不可訪問,在基類與派生類外不可訪向;基類的私有成員在第一級派生類中可以調(diào)用公有函數(shù)訪問,在第二級派生類中不可訪問命迈,在基類與派生類外不可訪問。
表5-2 私有繼承的訪問控制
第一級派生類中 | 第二級派生類中 | 基類與派生類外 | |
---|---|---|---|
基類的公有成員 | 直接訪問 | 不可訪問 | 不可訪問 |
基類的保護(hù)成員 | 直接訪問 | 不可訪問 | 不可訪問 |
基類的私有成員 | 調(diào)用公有函數(shù)訪問 | 不可訪問 | 不可訪問 |
保護(hù)繼承
保護(hù)繼承中火的,基類的公有成員和保護(hù)成員都以保護(hù)成員的身份出現(xiàn)在派生類中,而基類的私有成員不可以直接訪問壶愤。這樣,派生類的其他成員可以直接訪問從基類繼承來的公有和保護(hù)成員,但在類外通過派生類的對象無法直接訪問他們馏鹤。
三征椒、派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)
構(gòu)造函數(shù)與析構(gòu)函數(shù)
在執(zhí)行一個派生類的構(gòu)造函數(shù)之前,總是先執(zhí)行基類的構(gòu)造函數(shù)假瞬。派生類對象消亡時陕靠,先執(zhí)行派生類的析構(gòu)函數(shù),在執(zhí)行基類的析構(gòu)函數(shù)脱茉。
如果基類定義了帶有形參表的構(gòu)造函數(shù)剪芥,則派生類就應(yīng)當(dāng)定義構(gòu)造函數(shù)。
定義派生類構(gòu)造函數(shù)的格式
派生類名::派生類名(參數(shù)表):基類名1(基類1 初始化參數(shù)表),...,基類名m(基類m初始化參數(shù)表),成員對象名1(成員對象1 初始化參數(shù)表),...,成員對象名n(成員對象n 初始化參數(shù)表)
{
派生類構(gòu)造函數(shù)函數(shù)體 //其他初始化操作
}
程序5-15 基類和派生類的構(gòu)造函數(shù)與析構(gòu)函數(shù)
#include <iostream>
using namespace std;
class BaseClass
{
protected:
int v1,v2;
public:
BaseClass();
BaseClass(int,int);
~BaseClass();
};
BaseClass::BaseClass()
{
cout<<"BaseClass 無參構(gòu)造函數(shù)"<<endl;
}
BaseClass::BaseClass(int m,int n)
{
v1 = m;
v2 = n;
cout<<"BaseClass 2個參數(shù)構(gòu)造函數(shù)"<<endl;
}
BaseClass::~BaseClass()
{
cout<<"BaseClass 析構(gòu)函數(shù)"<<endl;
}
class DerivedClass:public BaseClass
{
int v3;
public:
DerivedClass();
DerivedClass(int);
DerivedClass(int,int,int);
~DerivedClass();
};
DerivedClass::DerivedClass()
{
cout<<"DerivedClass 無參構(gòu)造函數(shù)"<<endl;
}
DerivedClass::DerivedClass(int k):v3(k)
{
cout<<"DerivedClass 帶1個參數(shù)的構(gòu)造函數(shù)"<<endl;
}
DerivedClass::DerivedClass(int m,int n,int k):BaseClass(m,n),v3(k)
{
cout<<"DerivedClass 帶3個參數(shù)的構(gòu)造函數(shù)"<<endl;
}
DerivedClass::~DerivedClass()
{
cout<<"DerivedClass 析構(gòu)函數(shù)"<<endl;
}
int main()
{
cout<<"無參對象的創(chuàng)建"<<endl;
BaseClass baseCla;
DerivedClass derivedCla;
return 0;
}
無參對象的創(chuàng)建
BaseClass 無參構(gòu)造函數(shù)
BaseClass 無參構(gòu)造函數(shù)
DerivedClass 無參構(gòu)造函數(shù)
DerivedClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
例5-11 修改程序5-15
將主函數(shù)修改如下:
int main()
{
cout<<"帶參數(shù)對象的創(chuàng)建"<<endl;
BaseClass baseCla1(10,20);
DerivedClass derivedCla1(30);
return 0;
}
帶參數(shù)對象的創(chuàng)建
BaseClass 2個參數(shù)構(gòu)造函數(shù)
BaseClass 無參構(gòu)造函數(shù)
DerivedClass 帶1個參數(shù)的構(gòu)造函數(shù)
DerivedClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
例5-12
int main()
{
cout<<"無參對象的創(chuàng)建"<<endl;
BaseClass baseCla;
DerivedClass derivedCla;
cout<<"帶參數(shù)對象的創(chuàng)建"<<endl;
BaseClass baseCla1(10,20);
DerivedClass derivedCla1(30);
return 0;
}
無參對象的創(chuàng)建
BaseClass 無參構(gòu)造函數(shù)
BaseClass 無參構(gòu)造函數(shù)
DerivedClass 無參構(gòu)造函數(shù)
帶參數(shù)對象的創(chuàng)建
BaseClass 2個參數(shù)構(gòu)造函數(shù)
BaseClass 無參構(gòu)造函數(shù)
DerivedClass 帶1個參數(shù)的構(gòu)造函數(shù)
DerivedClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
DerivedClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
程序5-16 調(diào)用基類和派生類的構(gòu)造函數(shù)琴许、析構(gòu)函數(shù)和成員函數(shù)
#include <iostream>
using namespace std;
class Base
{
private:
int Y;
public:
Base(int y = 0)
{
Y = y;
cout<<"Base("<<y<<")"<<endl;
}
~Base()
{
cout<<"~Base()"<<endl;
}
void print()
{
cout<<Y<<" ";
}
};
class Derived:public Base
{
private:
int Z;
public:
Derived(int y,int z):Base(y)
{
Z = z;
cout<<"Derived("<<y<<","<<z<<")"<<endl;
}
~Derived()
{
cout<<"~Derived()"<<endl;
}
void print()
{
Base::print();
cout<<Z<<endl;
}
};
int main()
{
Derived d(10,20);
d.print();
return 0;
}
Base(10)
Derived(10,20)
10 20
~Derived()
~Base()
復(fù)制構(gòu)造函數(shù)
程序5-17 派生類中的復(fù)制構(gòu)造函數(shù)
#include <iostream>
using namespace std;
class A
{
public:
A()
{
i = 100;
cout<<"類A默認(rèn)構(gòu)造函數(shù)"<<endl;
}
A(const A &s)
{
i = s.i;
cout<<"類A復(fù)制構(gòu)造函數(shù)"<<endl;
}
int getValue();
void setValue(int);
private:
int i;
};
int A::getValue()
{
return i;
}
void A::setValue(int k)
{
i = k;
}
class B:public A //公有派生類
{
private:
float f;
public:
B()
{
f = 20.1;
cout<<"類B默認(rèn)構(gòu)造函數(shù)"<<endl;
}
B(const B &v):A::A(v),f(v.f)
{
cout<<"類B復(fù)制構(gòu)造函數(shù)"<<endl;
}
float getValue();
int getValue1()
{
return A::getValue();
}
};
float B::getValue()
{
return f;
}
int main()
{
A a;
B b;
B bb(b);
return 0;
}
類A默認(rèn)構(gòu)造函數(shù)
類A默認(rèn)構(gòu)造函數(shù)
類B默認(rèn)構(gòu)造函數(shù)
類A復(fù)制構(gòu)造函數(shù)
類B復(fù)制構(gòu)造函數(shù)
程序5-18 賦值運(yùn)算符的重載及使用
#include <iostream>
using namespace std;
class CBase
{
public:
CBase(){}
CBase(CBase & c)
{
cout<<"CBase::復(fù)制構(gòu)造函數(shù)"<<endl;
}
CBase & operator=(const CBase &b)
{
cout<<"CBase::operator="<<endl;
return *this;
}
};
class CDerived:public CBase
{
public:
CDerived()
{
cout<<"CDerived::復(fù)制構(gòu)造函數(shù)"<<endl;
}
};
int main()
{
CDerived d1,d2;
CDerived d3(d1); //d3初始化過程中會調(diào)用類CBase的復(fù)制構(gòu)造函數(shù)
d2 = d1; //會調(diào)用類CBase重載的“=”運(yùn)算符
return 0;
}
CDerived::復(fù)制構(gòu)造函數(shù)
CDerived::復(fù)制構(gòu)造函數(shù)
CBase::復(fù)制構(gòu)造函數(shù)
CBase::operator=
多重繼承的構(gòu)造函數(shù)與析構(gòu)函數(shù)
設(shè)計(jì)兩個基類BaseClass1和BaseClass2共同派生一個派生類DerivedClass税肪。
程序5-19 多重繼承
#include <iostream>
using namespace std;
class BaseClass1
{
protected:
int v1,v2;
public:
BaseClass1();
BaseClass1(int,int);
~BaseClass1();
void SetValue(int,int);
void PrintValue();
};
BaseClass1::BaseClass1():v1(0),v2(0)
{
cout<<"BaseClass1 無參構(gòu)造函數(shù)"<<endl;
}
BaseClass1::BaseClass1(int m,int n)
{
v1 = m;
v2 = n;
cout<<"BaseClass1 帶2個參數(shù)構(gòu)造函數(shù)"<<endl;
}
BaseClass1::~BaseClass1()
{
cout<<"BaseClass1 析構(gòu)函數(shù)"<<endl;
}
void BaseClass1::SetValue(int m,int n)
{
v1 = m;
v2 = n;
}
void BaseClass1::PrintValue()
{
cout<<"v1="<<v1<<"\tv2="<<v2;
}
class BaseClass2
{
protected:
int v1,v4;
public:
BaseClass2();
BaseClass2(int,int);
~BaseClass2();
void SetValue(int,int);
void PrintValue();
};
BaseClass2::BaseClass2():v1(1),v4(1)
{
cout<<"BaseClass2 無參構(gòu)造函數(shù)"<<endl;
}
BaseClass2::BaseClass2(int m,int n)
{
v1 = m;
v4 = n;
cout<<"BaseClass2 帶2個參數(shù)構(gòu)造函數(shù)"<<endl;
}
BaseClass2::~BaseClass2()
{
cout<<"BaseClass2 析構(gòu)函數(shù)"<<endl;
}
void BaseClass2::SetValue(int m,int n)
{
v1 = m;
v4 = n;
}
void BaseClass2::PrintValue()
{
cout<<"v1="<<v1<<"\tv4="<<v4;
}
class DerivedClass :public BaseClass1,public BaseClass2
{
public:
int v3;
public:
DerivedClass();
DerivedClass(int);
DerivedClass(int,int,int,int);
~DerivedClass();
void SetValue(int m,int n,int k,int h)
{
BaseClass1::SetValue(m,n);
BaseClass2::SetValue(2*m,h);
v3 = k;
}
void SetValue(int m,int n,int k)
{
BaseClass1::SetValue(m,n);
BaseClass2::SetValue(2*m,2*n);
v3 = k;
}
void SetValue(int m,int n)
{
BaseClass1::SetValue(m,n);
BaseClass2::SetValue(-1,-1);
v3 = -1;
}
void PrintValue();
};
DerivedClass::DerivedClass():BaseClass1(0,0),BaseClass2(0,0),v3(0)
{
cout<<"DerivedClass 無參構(gòu)造函數(shù)"<<endl;
}
DerivedClass::DerivedClass(int k)
{
v3 = k;
cout<<"DerivedClass 帶1個參數(shù)的構(gòu)造函數(shù)"<<endl;
}
DerivedClass::DerivedClass(int m,int n,int k,int t):BaseClass1(m,n),BaseClass2(m,t),v3(k)
{
cout<<"DerivedClass 帶4個參數(shù)的構(gòu)造函數(shù)"<<endl;
}
DerivedClass::~DerivedClass()
{
cout<<"DerivedClass 析構(gòu)函數(shù)"<<endl;
}
void DerivedClass::PrintValue()
{
BaseClass1::PrintValue();
cout<<"\tv3="<<v3<<endl;
BaseClass2::PrintValue();
cout<<endl;
}
int main()
{
cout<<"帶參數(shù)對象的創(chuàng)建"<<endl;
DerivedClass derivedCla1(1000,2000,3000,4000);
derivedCla1.PrintValue();
return 0;
}
帶參數(shù)對象的創(chuàng)建
BaseClass1 帶2個參數(shù)構(gòu)造函數(shù)
BaseClass2 帶2個參數(shù)構(gòu)造函數(shù)
DerivedClass 帶4個參數(shù)的構(gòu)造函數(shù)
v1=1000 v2=2000 v3=3000
v1=1000 v4=4000
DerivedClass 析構(gòu)函數(shù)
BaseClass2 析構(gòu)函數(shù)
BaseClass1 析構(gòu)函數(shù)
四、類之間的關(guān)系
類與類之間的關(guān)系
使用已有類編寫新的類有兩種方式:繼承和組合榜田。
封閉類的派生
如果一個類的成員變量是另一個類的對象益兄,則為封閉類。
定義封閉類構(gòu)造函數(shù)的形式
類名::類名(形參表):內(nèi)嵌對象1(形參表),內(nèi)嵌對象2(形參表),...
{
類體
}
程序5-20 封閉類的構(gòu)造函數(shù)
#include <iostream>
#include <string>
using namespace std;
class myDate
{
public:
myDate(); //構(gòu)造函數(shù)
myDate(int);
myDate(int,int);
myDate(int,int,int); //構(gòu)造函數(shù)
myDate(const myDate &d);
~myDate();
void setDate(int,int,int); //設(shè)置日期
void setDate(myDate); //設(shè)置日期
myDate getDate(); //獲取日期
void setYear(int); //設(shè)置年
int getMonth();//獲取月
void printDate() const; //打印日期
private:
int year,month,day; //成員變量箭券,表示年净捅、月、日
};
//在類體外定義成員函數(shù)
myDate::myDate()
{
year = 1970;
month = 1;
day = 1;
cout<<"myDate默認(rèn)構(gòu)造函數(shù)"<<endl;
}
myDate::myDate(int y)
{
year = y;
month = 1;
day = 1;
cout<<"myDate 帶1個參數(shù)的構(gòu)造函數(shù)"<<endl;
}
myDate::myDate(int y,int m)
{
year = y;
month = m;
day = 1;
cout<<"myDate 帶2個參數(shù)的構(gòu)造函數(shù)"<<endl;
}
myDate::myDate(int y,int m,int d)
{
year = y;
month = m;
day = d;
cout<<"myDate 帶3個參數(shù)的構(gòu)造函數(shù)"<<endl;
}
myDate::myDate(const myDate &d)
{
year = d.year;
month = d.month;
day = d.day;
cout<<"myDate_COPY 構(gòu)造函數(shù)"<<endl;
}
myDate::~myDate()
{
cout<<"myDate 析構(gòu)函數(shù)"<<endl;
}
void myDate::setDate(int y,int m,int d)
{
year=y;
month=m;
day=d;
return;
}
void myDate::setDate(myDate oneD)
{
year=oneD.year;
month=oneD.month;
day=oneD.day;
return;
}
myDate myDate::getDate()
{
myDate d;
d.year = year;
d.month = month;
d.day = day;
return d;
}
void myDate::setYear(int y)
{
year = y;
return;
}
int myDate::getMonth()
{
return month;
}
void myDate::printDate() const
{
cout<<year<<"/"<<month<<"/"<<day;
return;
}
class CStudent
{
public:
CStudent();
CStudent(string,myDate);
~CStudent();
void setStudent(string,myDate); //設(shè)置學(xué)生信息
void setName(string); //設(shè)置學(xué)生姓名
string getName(); //獲取姓名
void setBirthday(myDate); //設(shè)置生日
myDate getBirthday(); //獲取生日
void printInfo() const; //打印信息
private:
string name; //姓名
myDate birthday; //生日
};
CStudent::CStudent():name("Noname"),birthday(myDate())
{
cout<<"CStudent 默認(rèn)構(gòu)造函數(shù)"<<endl;
}
CStudent::CStudent(string str,myDate d):name(str),birthday(d)
{
cout<<"CStudent 有參構(gòu)造函數(shù)"<<endl;
}
CStudent::~CStudent()
{
cout<<"CStudent 析構(gòu)函數(shù)"<<endl;
}
void CStudent::setStudent(string s,myDate d)
{
name = s;
birthday.setDate(d);
return;
}
void CStudent::setName(string n)
{
name = n;
return;
}
string CStudent::getName()
{
return name;
}
void CStudent::setBirthday(myDate d)
{
birthday.setDate(d);
return;
}
myDate CStudent::getBirthday()
{
return birthday;
}
void CStudent::printInfo()const
{
cout<<"姓名: "<<name<<"\t生日: ";
birthday.printDate(); //調(diào)用類myDate的成員函數(shù)
cout<<endl;
}
class CUndergraduateStudent:public CStudent //本科生類辩块,繼承于 CStudent
{
private:
string department; //學(xué)生所屬的系名
public:
CUndergraduateStudent();
CUndergraduateStudent(string,myDate);
~CUndergraduateStudent();
void setDep(string);
void PrintInfo();
};
CUndergraduateStudent::CUndergraduateStudent()
{
cout<<"CUndergraduateStudent 默認(rèn)構(gòu)造函數(shù)"<<endl;
}
CUndergraduateStudent::CUndergraduateStudent(string str,myDate d):CStudent(str,d)
{
cout<<"CUndergraduateStudent 有參構(gòu)造函數(shù)"<<endl;
}
CUndergraduateStudent::~CUndergraduateStudent()
{
cout<<"CUndergraduateStudent 析構(gòu)函數(shù)"<<endl;
}
void CUndergraduateStudent::setDep(string dep)
{
department = dep;
}
void CUndergraduateStudent::PrintInfo()
{
CStudent::printInfo(); //調(diào)用基類的printInfo函數(shù)
cout<<"院系:\t"<<department<<endl<<endl;
}
int main()
{
CUndergraduateStudent s2("小張",myDate());
return 0;
}
myDate默認(rèn)構(gòu)造函數(shù)
myDate_COPY 構(gòu)造函數(shù)
myDate_COPY 構(gòu)造函數(shù)
CStudent 有參構(gòu)造函數(shù)
myDate 析構(gòu)函數(shù)
CUndergraduateStudent 有參構(gòu)造函數(shù)
myDate 析構(gòu)函數(shù)
CUndergraduateStudent 析構(gòu)函數(shù)
CStudent 析構(gòu)函數(shù)
myDate 析構(gòu)函數(shù)
*互包含關(guān)系的類
在處理相對復(fù)雜的問題而需要考慮類的組合時蛔六,很可能遇到兩個類相互引用的情況,稱為循環(huán)依賴废亭。
class A //類A的定義
{
public:
void f(B b); //以類B對象為形參的成員函數(shù)
};
class B //類B的定義
{
public:
void g(A a); //以類A對象為形參的成員函數(shù)
}
解決辦法是使用前向引用聲明国章。
在提供一個完整的類定義之前,不能定義該類的對象豆村,也不能在內(nèi)聯(lián)成員函數(shù)中使用該類的對象液兽。
例5-15 互包含的類
#include <iostream>
#include <string>
using namespace std;
class B; //前向引用聲明
class A
{
int a;
B b; //不完整的類型定義
};
class B
{
A a;
int b;
};
int main()
{
return 0;
}
程序5-21 互包含的類
#include <iostream>
#include <string>
using namespace std;
class B;
class A
{
public:
int aInt;
B *bPoint = NULL;
void SetValue(int v)
{
aInt = v;
}
};
class B
{
public:
A aCla;
int bInt;
void SetValue(int v)
{
bInt = v;
}
};
int main()
{
A ca;
B cb;
ca.bPoint = &cb;
cout<<"ca.bPoint="<<ca.bPoint<<endl;
cout<<"cb Addr="<<&cb<<endl;
cout<<"ca.aInt="<<ca.aInt<<endl;
cout<<"cb.aCLa.aInt="<<cb.aCla.aInt<<endl;
cout<<"cb.bInt="<<cb.bInt<<endl;
cout<<"分界線"<<endl;
ca.SetValue(10);
cb.SetValue(20);
cb.aCla = ca;
cout<<"ca.bPoint="<<ca.bPoint<<endl;
cout<<"ca.aInt="<<ca.aInt<<endl;
cout<<"cb.aCla.aInt="<<cb.aCla.aInt<<endl;
cout<<"cb.bInt="<<cb.bInt<<endl;
return 0;
}
ca.bPoint=0x6ffde0
cb Addr=0x6ffde0
ca.aInt=0
cb.aCLa.aInt=-1
cb.bInt=1
分界線
ca.bPoint=0x6ffde0
ca.aInt=10
cb.aCla.aInt=10
cb.bInt=20
五、多層次的派生
在C++中掌动,派生可以是多層次的四啰。
在C++中宁玫,類之間的繼承關(guān)系具有傳遞性。
在定義派生類時拟逮,只需寫直接基類撬统,不需要寫間接基類。
程序5-22 多級派生時構(gòu)造函數(shù)的調(diào)用
#include <iostream>
using namespace std;
class BaseClass1
{
protected:
int v1,v2;
public:
BaseClass1();
BaseClass1(int,int);
~BaseClass1();
};
BaseClass1::BaseClass1()
{
cout<<"BaseClass1 無參構(gòu)造函數(shù)"<<endl;
}
BaseClass1::BaseClass1(int m,int n):v1(m),v2(n)
{
cout<<"BaseClass1 帶2個參數(shù)構(gòu)造函數(shù)"<<endl;
}
BaseClass1::~BaseClass1()
{
cout<<"BaseClass1 析構(gòu)函數(shù)"<<endl;
}
class BaseClass2:public BaseClass1
{
protected:
int v3;
public:
BaseClass2();
BaseClass2(int);
BaseClass2(int,int,int);
~BaseClass2();
};
BaseClass2::BaseClass2()
{
cout<<"BaseClass2 無參構(gòu)造函數(shù)"<<endl;
}
BaseClass2::BaseClass2(int m):v3(m)
{
cout<<"BaseClass2 帶1個參數(shù)構(gòu)造函數(shù)"<<endl;
}
BaseClass2::BaseClass2(int m,int n,int k):BaseClass1(m,n),v3(k)
{
cout<<"BaseClass2 帶3個參數(shù)構(gòu)造函數(shù)"<<endl;
}
BaseClass2::~BaseClass2()
{
cout<<"BaseClass2 析構(gòu)函數(shù)"<<endl;
}
class DerivedClass:public BaseClass2
{
public:
int v4;
public:
DerivedClass();
DerivedClass(int);
DerivedClass(int,int,int,int);
~DerivedClass();
};
DerivedClass::DerivedClass()
{
cout<<"DerivedClass 無參構(gòu)造函數(shù)"<<endl;
}
DerivedClass::DerivedClass(int k):v4(k)
{
cout<<"DerivedClass 帶1個參數(shù)構(gòu)造函數(shù)"<<endl;
}
DerivedClass::DerivedClass(int m,int n,int k,int t):BaseClass2(m,n,k),v4(t)
{
cout<<"DerivedClass 帶4個參數(shù)構(gòu)造函數(shù)"<<endl;
}
DerivedClass::~DerivedClass()
{
cout<<"DerivedClass 析構(gòu)函數(shù)"<<endl;
}
int main()
{
cout<<"無參對象的創(chuàng)建"<<endl;
DerivedClass derivedCla;
return 0;
}
無參對象的創(chuàng)建
BaseClass1 無參構(gòu)造函數(shù)
BaseClass2 無參構(gòu)造函數(shù)
DerivedClass 無參構(gòu)造函數(shù)
DerivedClass 析構(gòu)函數(shù)
BaseClass2 析構(gòu)函數(shù)
BaseClass1 析構(gòu)函數(shù)
將程序5-22的主函數(shù)修改如下
int main()
{
cout<<"帶參數(shù)對象的創(chuàng)建"<<endl;
DerivedClass derivedCla1(1000,2000,3000,4000);
return 0;
}
帶參數(shù)對象的創(chuàng)建
BaseClass1 帶2個參數(shù)構(gòu)造函數(shù)
BaseClass2 帶3個參數(shù)構(gòu)造函數(shù)
DerivedClass 帶4個參數(shù)構(gòu)造函數(shù)
DerivedClass 析構(gòu)函數(shù)
BaseClass2 析構(gòu)函數(shù)
BaseClass1 析構(gòu)函數(shù)
六敦迄、基類與派生類指針的互相轉(zhuǎn)換
對于指針類型,可以使用基類指針指向派生類對象凭迹,也可以將派生類的指針直接賦值給基類指針罚屋。
但即使基類指針指向的是一個派生類的對象,也不能通過基類指針訪問基類中沒有而僅在派生類中定義的成員函數(shù)嗅绸。
當(dāng)派生類指針指向基類對象時脾猛,必須要將基類對象進(jìn)行強(qiáng)制類型轉(zhuǎn)換,才能賦給派生類指針鱼鸠。
程序5-23 使用指針的情況
#include <iostream>
using namespace std;
class CBase
{
protected:
int n;
public:
CBase(int i):n(i){}
void Print()
{
cout<<"CBase:n="<<n<<endl;
}
};
class CDerived:public CBase
{
public:
int v;
CDerived(int i):CBase(i),v(2*i){}
void Func(){};
void Print()
{
cout<<"CDerived:n="<<n<<endl;
cout<<"CDerived:v="<<v<<endl;
}
};
int main()
{
CDerived objDerived(3);
CBase objBase(5);
CBase *pBase = &objDerived; //使用基類指針指向派生類對象
CDerived *pDerived;
pDerived = &objDerived;
cout<<"使用派生類指針調(diào)用函數(shù)"<<endl;
pDerived->Print(); //調(diào)用的時派生類中的函數(shù)
pBase = pDerived; //基類指針 = 派生類指針猛拴,正確
cout<<"使用基類指針調(diào)用函數(shù)"<<endl;
pBase->Print(); //調(diào)用的是基類中的函數(shù)
//pBase->Func(); //錯誤,通過基類指針不能調(diào)用派生類函數(shù)
//pDerived = pBase //派生類指針 = 基類指針
pDerived = (CDerived *)pBase; //強(qiáng)制類型轉(zhuǎn)換蚀狰,派生類指針 = 基類指針
cout<<"使用派生類指針調(diào)用函數(shù)"<<endl;
pDerived->Print(); //調(diào)用的是派生類的函數(shù)
return 0;
}
使用派生類指針調(diào)用函數(shù)
CDerived:n=3
CDerived:v=6
使用基類指針調(diào)用函數(shù)
CBase:n=3
使用派生類指針調(diào)用函數(shù)
CDerived:n=3
CDerived:v=6