版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第4章继承性授课内容4.1继承与派生的概念4.2
派生类的声明方式4.3
派生类的构成4.4派生类中基类成员的访问属性4.5派生类相对于基类的变化4.6
派生类的构造函数和析构函数4.7基类与派生类对象的关系4.8多重继承4.1继承与派生的概念8.1继承与派生为什么使用继承?(具体化、特殊化)使用继承,可实现代码的重用,进而提高代码的易维护性。水果桃梨苹果莱阳梨红富士秦冠继承性概述两个类之间的一种关系,当一个类拥有另一个类的所有属性和行为时,就称这两个类之间具有继承关系。被继承的类称为父类或基类,继承了父类属性和行为的类称为子类或派生类。继承性概述Question:如何设计类?行为吃饭、睡觉、讲课属性身高、体重、讲授课程教师行为吃饭、睡觉、听课属性身高、体重、所在班级学生行为吃饭、睡觉属性身高、体重人继承性概述行为讲课属性讲授课程教师:继承人行为听课属性所在班级学生:继承人行为吃饭、睡觉属性身高、体重人继承性概述派生类继承了基类除构造函数与析构函数之外的全部成员。派生类可以改造基类的成员继承性概述根据基类的个数,继承分为:单继承:子类只有一个直接基类。ShapeTwoDShapeThreeDShapeCircleSquareTriangle继承性概述根据基类的个数,继承分为:多继承:子类有多个直接基类。职员在职研究生研究生设计程序时尽量少使用多继承。基类和派生类的关系,可以表述为:
派生类是基类的具体化,而基类是派生类的抽象。4.1继承与派生的概念4.2派生类的声明方式4.2派生类的声明方式根据继承的方式,继承分为:公有继承私有继承:默认方式保护继承派生类的定义格式:class派生类名
:继承方式基类1,继承方式基类2,…{ 派生类中增加的成员声明与定义; };4.2派生类的声明方式4.编程举例:classPerson{protected: stringm_szName; stringm_szSex;public: voidShowP() {cout<<m_szName<<"\t"<<m_szSex<<endl; }};classEmployee:publicPerson{ stringm_szDept;public: voidShowE() {cout<<m_szName<<"\t"<<m_szSex<<"\t"<<m_szDept<<endl; } };Employeeemp;emp.ShowP();emp.ShowE();4.2派生类的声明方式5.编程举例:多继承classPlane{ charchPropeller;public: voidFlight();};classBoat{ charchHelm;public: voidFloat();};classSeaplane :publicPlane,publicBoat{ };编程实现4.3派生类的构成派生类中的成员包括:从基类继承过来的成员自己新增加的成员从基类继承过来的成员体现了派生类从基类继承而获得的共性,而新增加的成员体现了派生类的个性,体现了派生类与基类的不同,体现了不同派生类的区别。4.3派生类的构成4.3派生类的构成派生类对象的构成公有成员保护成员私有成员公有成员保护成员私有成员继承部分新定义部分派生类成员派生类classBase
//声明基类{public://基类公用成员
voidsetx(intn){x=n;}
int
getx(){returnx;}voidshowx(){cout<<"Baseclass:x="<<x<<endl;}private://基类私有成员
intx;};第4章继承与组合//以public方式声明派生类Derived
classDerived:
publicBase{public:voidsety(intn){y=n;}
int
gety(){returny;}voidshowy()
{cout<<"Derivedclass:y="<<y<<endl;}private:
inty;};第4章继承与组合第4章继承与组合图4-3基类Base和派生类Derived的成员示意图
voidsetx();
int
getx();voidshowx();
intx;Base类
voidsetx();
int
getx();voidshowx();intx;Derived类
voidsety();
int
gety();voidshowy();inty;继承新增数据成员成员函数注:ClassA{public:
intx;};ClassB:publicA{public;
inty;};Bb;ClassC{public:
intx,y;};可否认为b是C类的对象?逻辑上可以,本质上不是。实际上,对象b创建过程中会首先创建一个基类A的隐含对象。实际上,并不是把基类的成员和派生类自己新增加的成员简单地加在一起就成为派生类。构造一个派生类一般经历3个步骤:
1.从基类接收成员
2.调整从基类接收的成员
3.增加新成员。4.3派生类的构成Question:某信息管理系统中,定义人Person类,包括数据成员:姓名、年龄,成员函数:获得年龄、信息设置、信息显示;另外,需要定义学生Student类,包括数据成员:姓名、年龄、学号,成员函数:获得年龄、获得学号、信息设置、信息显示。请定义Person类和Student类。classPerson{ stringm_sName;
int
m_iAge;public:
int
GetAge()const;voidSet(stringname,intage); voidShow()const;};classStudent:Person?{
int
m_iNumber;public:
int
GetNumber()const;voidSetStudent(stringname,intage,intnumber);voidShowStudent()const;};采用哪种继承方式?4.4派生类的继承方式派生类的继承方式—回顾classTest{
inta1; voidf1(){cout<<a1;}proteced:
inta2; voidf2(){cout<<a2;}public:
inta3; voidf3(){cout<<a3;} voidshow{f1();f2();f3()}};intmain(){Testt;
cout<<t.a1;
cout<<t.a2;
cout<<t.a3;t.f1();t.f2();t.f3();
t.show();return0;}派生类的继承方式(访问权修饰符)继承方式
public:
公有继承
protected:
保护继承
private:
私有继承通过继承方式,可以调整从基类中继承下来的成员的访问控制权限。公有继承继承方式基类成员访问权限继承到派生类后访问权限公有继承
publicpublicprotectedprotectedprivate不可访问编程举例
Classx{Private:
inta;Protected:
intb;Public:
intc;};y1的构成:不可访问:私有:保护:公有:Classy1:publicx{
intd;};adbc保护继承继承方式基类成员访问权限继承到派生类后访问权限保护继承
publicprotectedprotectedprotectedprivate不可访问编程举例
Classx{Private:
inta;Protected:
intb;Public:
intc;};y1的构成:不可访问:私有:保护:公有:Classy1:protectedx{
intd;};adbc私有继承继承方式基类成员访问权限继承到派生类后访问权限私有继承
publicprivateprotectedprivateprivate不可访问编程举例
Classx{Private:
inta;Protected:
intb;Public:
intc;};y1的构成:不可访问:私有:保护:公有:Classy1:publicx{
intd;};adbc程序改错classA{
int
m_Private;protected:
int
m_Protected;public:
int
m_Pulbic;};int
main(){Bb;b.SetNum();
b.m_Public=10;
b.m_protected=10;
b.m_Private=10;return0;}classB:publicA{public: voidSetNum() {m_Protected=1;
m_Pulbic=1;
m_Private=1; }};classA{
int
m_Private;protected:
int
m_Protected;public:
int
m_Pulbic;};int
main(){Bb;b.SetNum();
b.m_Pulbic=10;
b.m_protected=10;
b.m_Private=10;return0;}classB:protectedA{public: voidSetNum() {m_Protected=1;
m_Pulbic=1;
m_Private=1; }};多层继承ex8_inherit
classA{public:voidf1();protected:intj1;private:inti1;};classB:publicA{public:voidf2();protected:intj2;private:inti2;};classC:publicB{public:voidf3();};1.f2()能否访问基类A中的成员:f1(),i1,j1?可以访问f1(),j1,不可访问i1;2.派生类B的对象b1能否访问基类A中的成员:f1(),i1,j1?可以访问f1(),不可访问i1和j1;3.f3()能否访问直接基类B中的成员:f2(),j2和i2?能否访问间接基类A中的成员:f1(),j1和i1?可以访问f2()和j2,f1()和j1,不可访问i1和i2;4.C类的对象c1能否访问f2(),i2,j2?能否访问f1(),i1,j1?可以访问f2()和f1();classA{
int
m_Private;protected:
int
m_Protected;public:
int
m_Pulbic;};int
main(){Bb;b.SetNum();
b.m_Pulbic=10;
b.m_protected=10;
b.m_Private=10;return0;}classB:privateA{public: voidSetNum() {m_Protected=1;
m_Pulbic=1;
m_Private=1; }};结论:在公有继承时,派生类的成员函数可访问基类中的公有成员和保护成员,派生类对象仅可访问基类中的公有成员。思考:将两处public改为private呢?练习:My8_2classPerson{ stringm_sName;
int
m_iAge;public:
int
GetAge()const;voidSet(stringname,intage); voidShow()const;};classStudent:Person?{
int
m_iNumber;public:
int
GetNumber()const;voidSetStudent(stringname,intage,intnumber);voidShowStudent()const;};采用哪种继承方式?privateprotectedpublic如何实现?voidShowStudent(){cout<<"Name:"<<m_sName<<"Age:"<<m_iAge
<<"Number:"<<m_iNumber
<<endl; }protected:
编程注意:
当不允许外部访问一个类的数据成员,而允许该类的派生类访问该数据成员时,把数据成员定义为保护成员编程实现classPerson{ stringm_sName;
int
m_iAge;public:
int
GetAge()const;voidSet(stringname,intage); voidShow()const;};classStudent:publicPerson{ int
m_iNumber;public:
int
GetNumber()const;voidSetStudent(stringname,intage,intnumber); voidShowStudent();};protected:Show()const;
SetStudentstudent1;Student1.Show();Student1.Set(“LiYang”,20);
4.5派生类相对于基类的变化派生类相对于基类的变化派生类相对于基类的变化,主要体现在:派生类对基类的扩充派生类中的成员对基类成员的隐藏派生类对基类的扩充增加新成员classP//人{protected: charname[10];
intsex;public: voidShowP() {
cout<<name <<sex; }};classE:publicP//员工{chardept[20];public:
voidShowE(){
cout<<name <<sex <<dept;} };Eemp;emp.ShowP();emp.ShowE();派生类对基类的扩充集合基类成员classPlane{ charchPropeller;public: voidFlight();};classBoat{ charchHelm;public: voidFloat();};classSeaplane:publicPlane,publicBoat{};Seaplanesp;sp.Flight();sp.Float();派生类相对于基类的变化派生类相对于基类的变化,主要体现在:派生类对基类的扩充派生类中的成员对基类成员的隐藏派生类中的成员对基类成员的隐藏classP//人{protected: charname[10];
intsex;public: voidShowP() {
cout<<name <<sex; }};Eemp;emp.ShowP();emp.ShowE();classE:publicP//员工{chardept[20];public:voidShowE(){
cout<<name <<sex <<dept;} };Show()Show()Eemp;emp.Show();classB{protected:
int
mb;intma;public: B(intx,inty) :mb(x),ma(y) {}};classD:publicB{int
md;
intma;public:D(intj,intk,intl,intm) :B(j,k),md(l),ma(m){}voidSetA(intv){ma=v;}
int
GetA()const{returnma;}};intmain(){Dod(1,2,3,4);
cout<<od.GetA();
od.SetA(100);
cout<<od.GetA();return0;}指D中的maclassB{protected:
int
mb;public: B(intx):mb(x) {} voidSet(intx) {mb=x;}};classD:publicB{int
md;public:
D(intj,intk):B(j),md(k){}voidSet(intx,inty){mb=x;md=y;}voidPrint()const{cout<<mb<<md;}};intmain(){Dod(1,2);od.Print();
od.Set(10);od.Print();
od.Set(100,200);od.Print();return0;}调用出错派生类中的成员对基类成员的隐藏结论如果派生类定义的某个成员的名字和基类中的某个成员的名字相同,则称派生类隐藏了基类同名的成员。注意:无论派生类与基类的同名成员函数的参数是否相同,派生类都会隐藏基类同名的成员。classB{protected:
int
mb;public: B(intx):mb(x) {} voidSet(intx) {mb=x;}};classD:publicB{int
md;public:
D(intj,intk):B(j),md(k){}voidSet(intx,inty){mb=x;md=y;}voidPrint()const{cout<<mb<<md;}};intmain(){Dod(1,2);od.Print();
od.Set(10);od.Print();
od.Set(100,200);od.Print();return0;}调用出错Question:派生类D对象如何访问基类B的set函数?派生类中的成员对基类成员的隐藏Question:如何访问基类中被隐藏的数据成员?Answer:显示访问基类成员
显式访问基类成员How?类成员访问方式隐式访问“对象名.成员名”或“成员名”。显式访问类名::成员名举例:emp.ShowMe();//emp.Employee::ShowMe();returnm_szName;//returnPerson::m_szName;
显式访问基类成员When?派生类对基类成员的显式访问派生类与基类有重名的成员,显式访问某个成员。派生类employee的成员函数ShowMevoidShowMe()//派生类与基类都有ShowMe(){ Person::ShowMe();
cout<<"something"<<endl;}显式访问基类成员
When?多继承派生,多个基类中有同名成员,将在派生类中产生歧义性,通过显式访问消除歧义性。classA {public: charm_szName[20];…}classB {public: charm_szName[20];…}classC:publicA,publicB { … }char*C::GetName(){ returnm_szName;}//Error!char*C::GetName(){ returnA::m_szName;}//
OK!多继承派生类具有多个基类。基类1基类2基类n…派生类classPerson{ stringm_sName;
int
m_iAge;public:
int
GetAge()const;voidSet(stringname,intage); voidShow()const;};classStudent:publicPerson{ int
m_iNumber;public:
int
GetNumber()const;voidSetStudent(stringname,intage,intnumber); voidShowStudent();};protected:Show()const;
SetStudentstudent1;student1.Show();student1.Set(“LiYang”,20);//student1.Student::Show();
//error!student1.Person::Set(“LiYang”,20);练习:实现Student类中的Set和Show函数。voidStudent::Set(stringname,intage,intnumber){
Person::Set(name,age);
m_iNumber=number;}voidStudent::Show(){
Person::Show();
cout<<"Number:"<<m_iNumber<<endl;}Question:为Person类和Student类添加构造函数,可以初始化Person类和Student类对象。4.6派生类的构造函数和析构函数派生类的构造函数和析构函数回顾:派生类不继承构造函数和析构函数派生类的组成?公有成员保护成员私有成员公有成员保护成员私有成员继承部分新定义部分派生类成员注意:以基类子对象的形式存在派生类的构造函数与析构函数回顾:派生类对象的创建过程231首先,创建基类的隐含对象然后,创建内嵌对象(如果存在)最后,创建派生类对象派生类的构造函数与析构函数回顾:派生类对象的撤销过程3首先,撤销基类的隐含对象2然后,撤销内嵌对象(如果存在)1首先撤消派生类对象
派生类的构造函数与析构函数概述派生类新增成员的初始化工作,由派生类的构造函数完成。从基类继承的成员的初始化工作,由基类的构造函数完成。必须在派生类中对基类的构造函数所需要的参数进行设置。思考:基类构造函数的调用应该在何时?在派生类构造函数体中可以吗?派生类构造函数派生类::派生类(参数总表) :基类1(参数表1),基类2(参数表2),…
内嵌对象1(对象参数表1),…
派生类新增数据成员1(初值1),…{ 派生类中新增成员的初始化; }格式初始化列表派生类的构造函数与析构函数派生类构造函数说明:若派生类为单继承,声明中只有一个基类名;若派生类为多继承,声明中有多个基类名。单继承举例classB{public: B(intx,inty) :b1(x),b2(y) {}private:
intb1;protected:
intb2;};classD:publicB{public:
D(int
j,intk,intl,intm);protected:
intd1;private:
intd2;};D::D(int
j,int
k,int
l,intm) :B(j,k),
d1(l),d2(m){}Dobj(4,5,6,7);调用基类的构造函数来初始化从基类继承的数据成员b1和b2派生类对象obj创建初始化过程示意图Dobj(4,5,6,7);d2d1b2b1obj继承部分新定义部分派生类成员D::D(int
j,int
k,int
l,intm) :B(j,k)
,
d1(l),d2(m){}=4=5=6=7B(intx,inty):b1(x),b2(y){}classB{public: B(intx,inty) :b1(x),b2(y) {}private:
intb1;protected:
intb2;};classD:publicB{public:
D(int
j,intk,intl,intm);protected:
intd1;private:
intd2;};D::D(int
j,int
k,int
l,intm) :B(j,k),
d1(l),d2(m){}Dobj(4,5,6,7);调用基类的构造函数来初始化从基类继承的数据成员b1和b2B():b1(0),b2(0) {}B(),有必要写出吗?派生类的构造函数与析构函数派生类构造函数说明:若派生类为单继承,声明中只有一个基类名;若派生类为多继承,声明中有多个基类名。若基类使用默认构造函数,声明中可省略基类名(参数表)项;classB{public:
B():b1(0),b2(0) {}private:
intb1;protected:
intb2;};classD:publicB{public:D(intl,intm);protected:
intd1;private:
intd2;};D::D(intl,intm) :d1(l),d2(m){}Dobj(6,7);隐含调用基类缺省构造函数怎样写D类构造函数?;派生类的构造函数与析构函数派生类构造函数说明:若派生类为单继承,声明中只有一个基类名;若派生类为多继承,声明中有多个基类名。若基类使用默认构造函数,声明中可省略基类名(参数表)项;若此时派生类新增成员不需初始化,可以不定义派生类构造函数。classB{public:
B():b1(0),b2(0) {}private:
intb1;protected:
intb2;};classD:publicB{public:D(){}};Dobj;派生类无新增成员或者新增成员不需要初始化时,可以省略派生类构造函数含有内嵌对象的类的构造函数举例classB{public: B(intx,inty) :b1(x),b2(y) {}private:
intb1;protected:
intb2;};classD{public:protected:
Bd1;private:
intd2;};D::D(int
j,int
k,intl)
:d1(j,k),
d2(l){}Dobj(4,5,6);调用B类的构造函数来初始化内嵌对象b1怎样写构造函数?D(int
j,intk,intl);派生类对象obj创建初始化过程示意图Dobj(4,5,6);内嵌对象d1D类成员D::D(int
j,int
k,intl) :d1(j,k)
,
d2(l){}d2d1.b2d1.b1obj=4=5=6B(intx,inty):b1(x),b2(y){}classB{public:
B() :b1(0) {}private:
intb1;};classD{public:protected:
Bd1;private:
intd2;};D::D(intj)
:d1(),
d2(l){}Dobj(4,5,6);调用B类的缺省构造函数来初始化内嵌对象b1怎样写构造函数?D(intj);引入规则的举例举例classB{public:
B(intm):b1(m) {}protected:
intb1;};classD:publicB{public:
D(intm,intn)
{b1=m;d1=n;}protected:
intd1;};Dobj(6,7);思考:有问题吗?引入规则的举例举例classB{public:
B(intm):b1(m) {}protected:
intb1;};classD{public:
D(intm,intn)
{d1.b1=m;d2=n;}protected:Bd1;
intd2;};Dobj(6,7);思考:有问题吗?规则:能在初始化列表中初始化的成员,尽量在初始化列表中初始化。8.3派生类的构造函数与析构函数派生类构造函数(续)派生类构造函数的执行顺序:按照基类被继承时声明的顺序,调用基类构造函数。按照内嵌对象在派生类中声明的顺序,调用内嵌对象的构造函数。执行派生类构造函数。classC{intmc;public: C(inti):mc(i) { cout<<"构造C" <<mc<<endl; }};classB{Cc1;Cc2;
int
mb;public:
B(inti,intj,intk);};intmain(){Bb(5,6,7);return0;}classA{protected:
intma;public:A(inti):ma(i){cout<<"构造A"<<endl;}};B::B(inti,intj,intk) :c1(i),c2(j),mb(k){
cout<<"构造B"<<endl;}:publicABb(5,6,7,8);B(inti,intj,intk,intl);B::B(inti,intj,intk,intl)c2(j),c1(i),:A(i),c1(j),c2(k),mb(l)初始化内嵌对象时构造函数的调用与声明顺序一致,而与初始化列表中的顺序无关classC{protected:
intmc;public: C(inti):c(i) { cout<<"构造C" <<mc<<endl; }};classB:publicA,publicC{int
mb;public:
B(inti,intj,intk);};intmain(){Bb(5,6,7);return0;}classA{protected:
intma;public:A(inti):ma(i){cout<<"构造A"<<endl;}};B::B(inti,intj,intk) :A(i),C(j),mb(k){
cout<<"构造B"<<endl;}
C(j),A(i),基类构造函数的调用与声明顺序一致,而与初始化列表中的顺序无关
派生类的构造函数与析构函数派生类析构函数派生类与基类的析构函数彼此独立,只作各自对象消亡前的善后工作。派生类析构函数的执行顺序:执行派生类析构函数。按照内嵌对象在派生类中声明的相反顺序,调用内嵌对象的析构函数。按照基类被继承时声明的相反顺序,调用基类析构函数。编程举例:example8_3My8_1Question:为Person类和Student类添加构造函数,可以初始化Person类和Student类对象。classPerson{
stringm_sName;
int
m_iAge;public:
int
GetAge()const;voidSet(stringname,intage); voidShow()const;};classStudent:publicPerson{ int
m_iNumber;public:
int
GetNumber()const;voidSetStudent(stringname,intage,intnumber); voidShowStudent()const;};protected:ClassPerson{……public:
Person(stringname,intage);};Person::Person(stringname,intage):m_sName(name),m_iAge(age){}ClassStudent{……public:Student(stringname,intage,intnumber);};Student::Student(stringname,intage,intnumber):Person(name,age),m_iNumber(number){}练习正方形:中心点坐标:(x,y),一顶点坐标:(x1,y1)面积:2*((x-x1)*(x-x1)+(y-y1)*(y-y1));声明一个Shape(形状)基类,它有两个派生类:Circle(圆)和Square(正方形),要求:(1)根据给出的圆心坐标和半径计算圆的面积;(2)根据给出的正方形中心坐标和一个顶点坐标计算正方形的面积。ShapeCircleSquare//shape.h的内容classShape{protected: doublem_dX;//中心点x坐标
doublem_dY;//中心点y坐标public: Shape(doublex,doubley) :m_dX(x),m_dY(y) {} doubleGetX()const{returnm_dX;} doubleGetY()const{returnm_dY;} voidSetX(intx){m_dX=x;} voidSetY(inty){m_dY=y;}};//circle.h的内容#include"shape.h"classCircle:publicShape{ doublem_dR;public: Circle(doublex,doubley,doubler) :Shape(x,y),m_dR(r) {} doubleGetArea()const {return3.14*m_dR*m_dR;}};//square.h的内容#include"shape.h"classSquare:publicShape{ doublem_dX1; doublem_dY1;public: Square(doublex,doubley, doublex1,doubley1) :Shape(x,y),m_dX1(x1),m_dY1(y1) {} doubleGetArea()const;};//square.cpp的内容#include"square.h"doubleSquare::GetArea()const{ return2*((m_dX-m_dX1)*(m_dX-m_dX1)+(m_dY-m_dY1)*(m_dY-m_dY1));}//main.cpp的内容#include"circle.h"#include<iostream>usingnamespacestd;intmain(){ Circlec1(1,1,10);
cout<<c1.GetArea()<<endl; return0;}shape.h文件的内容classShape{//…};circle.h文件的内容#include"shape.h"classCircle :publicShape{//…};square.h文件的内容#include"shape.h"classSquare :publicShape{//…};main.cpp文件
#include"circle.h"
#include"square.h"
intmain() { //用到了Circle类
//用到了Square类
return0;
}#include"shape.h"classCircle :publicShape{};#include"shape.h"classSquare :publicShape{};Shape.h文件被包含2次,怎么办?多文件程序Question:
Shape.h文件被包含2次,怎么办?Answer:预处理命令条件编译条件编译条件编译命令是用来定义某些编译内容要在一定条件下才参与编译的,否则不参与编译。格式一:
#ifdef<标识符><程序段1>#else<程序段2>
#endif功能:当<标识符>被定义过,则<程序段1>参与编译,否则<程序段2>参与编译。
#ifdef<标识符>或<程序段1>
#endif条件编译格式二:
#ifndef<标识符><程序段1>#else<程序段2>
#endif功能:当<标识符>被未定义过,则<程序段1>参与编译,否则<程序段2>参与编译。
#ifndef<标识符>或<程序段1>
#endif多文件程序#include<iostream>usingnamespacestd;intmain(){
cout<<"YYYYYYYYY"<<endl; #ifndefA
cout<<"XXXXXXXXX"<<endl;#endifreturn0;}#defineA参与编译,形成目标代码不参与编译,不形成目标代码条件编译格式三:#if<条件1><程序段1>#elif<条件2><程序段2>……#elif<条件n><程序段n>#else<缺省程序段>
#endif例:#include<iostream>usingnamespacestd;#defineA10voidmain(){#if(A>0)
cout<<"a>0"<<endl;#elif(A<0)
cout<<"a<0"<<endl;#else
cout<<"a==0"<<endl;#endif}与c++的if语句的用法很相似,但有根本区别:If语句控制着某些语句是否执行,而#if指令控制着某个程序段是否被编译。多文件程序//test.h的内容
classTest {inta; public: Test(intn):a(n) {} };//main.cpp的内容
#include"test.h"
intmain(){ Testt(10); return0;} #include"test.h"多文件程序//main.cpp的内容
#include"test.h" #include"test.h"
intmain() { Testt(10); return0; } classTest{ inta;public: Test(intn):a(n) {}};classTest{ inta;public: Test(intn):a(n) {}};intmain(){ Testt(10); return0;}预编译多文件程序//test.h的内容
#ifndefTEST_H#defineTEST_H classTest {inta; public: Test(intn):a(n) {} }; #endif//main.cpp的内容
#include"test.h"#include"test.h"
intmain(){ Testt(10); return0;} 多文件程序main.cpp的内容
#include"test.h" #include"test.h"
intmain() { Testt(10); return0; } #ifndefTEST_H#defineTEST_HclassTest{ inta;public: Test(intn):a(n) {}};#endif#ifndefTEST_H#defineTEST_HclassTest{ inta;public: Test(intn):a(n) {}};#endif………多文件程序任何一个头文件都应该避免重复包含,避免重复包含的办法如下:(对于头文件abc.h)在头文件的开头加上
#ifndefABC_H#defineABC_H在头文件的最后加上
#endifReturnquestionshape.h文件的内容classShape{//…};circle.h文件的内容#include"shape.h"classCircle :publicShape{//…};square.h文件的内容#include"shape.h"classSquare :publicShape{//…};main.cpp文件
#include"circle.h"
#include"square.h"
intmain() { //用到了Circle类
//用到了Square类
return0;
}#include"shape.h"classCircle :publicShape{};#include"shape.h"classSquare :publicShape{};Shape.h文件被包含2次,怎么办?条件编译开发C++程序的步骤开发C++程序的步骤建模编程连接调试运行
C++程序的编译过程分为预处理和正式编译两个步骤。在编译C++程序时,编译系统中的预处理模块首先根据预处理命令对源程序进行适当的加工,然后再正式编译。编译阶段形成扩展名为.obj二进制目标文件。编译注意:编译预处理对宏、包含指令、条件编译指令等进行处理词法语法分析将源代码翻译成中间代码(一般是汇编)优化代码将中间代码翻译成机器语言(目标文件),Ctrl+F7开发C++程序的步骤建模编译编程调试运行连接阶段形成扩展名为.exe二进制可执行文件连接开发C++程序的步骤建模编译编程调试运行连接开发C++程序的步骤建模编译编程连接运行调试Ctrl+F5输入、编译、调试和运行一个C++程序C++程序a.hb.h……a.cppb.cppc.cpp…………a.cppb.cppc.cpp……预处理正式编译a.objb.objc.obj……连接其他obj文件.exe文件引入classPerson{protected:
stringm_sName;
int
m_iAge;public:Person(conststringname,intage);
int
GetAge()const; voidShow()const;};//实现省略引入classStudent:publicPerson{int
m_iNumber;public:Student(conststringname,intage,intnumber);
int
GetNumber()const;voidShow()const;};//实现省略引入classTeacher:publicPerson{ stringm_sClass;public:Teacher(conststringname,intage,conststringsc);
int
GetNumber()const;voidShow()const;};//实现省略
引入Question:
定义函数,实现如下功能:显示Person类、Student类和Teacher类对象的年龄。voidShowAge(obj){
cout<<obj.GetAge()<<endl;}Answer:
1.重载ShowAge函数。//缺点?
2.?什么类型?4.7基类与派生类对象的关系基类与派生类之间的转换回顾:当一个类拥有另一个类的所有属性和行为时,就称这两个类之间具有继承关系。继承是一个具体化、特殊化的过程。personTeacherStudent继承体现了“isa”的关系。基类与派生类之间的转换在任何需要基类对象的地方都可以用公有派生类的对象来代替,这条规则称赋值兼容规则。派生类的对象可以给基类对象赋值派生类的对象可以初始化基类的引用基类的指针也可以指向派生类对象不常用常用,多态的前提常用,多态的前提概念(补充)继承方式表现前提:公有继承问题总结补充派生类对象对基类对象赋值
1.派生类的对象可以给基类的对象赋值基类数据成员基类成员函数
基类基类数据成员基类成员函数派生类新增数据成员新增成员函数赋值时此部分舍去不用Question:反过来可以吗?Answer:不可以!??classA{ intma;public: A(inti):ma(i) {}
int
GetA()const {returnma;}};classB:publicA{int
mb;public:B(inti,intj):A(i),mb(j){}
int
GetB()const{returnmb;}};intmain(){AobjA(3);BobjB(7,8);
objA=objB;
cout<<objA.GetA();
cout<<objA.GetB(); return0;}//Error!注意:赋值后不能企图通过基类对象访问派生类成员。objAma=3objBma=7mb=8GetA()GetB()ma=7派生类对象初始化基类引用2.派生类的对象可以初始化基类的引用基类数据成员基类成员函数objB派生类数据成员派生类成员函数rABobjB;A&rA=objB;注意:rA只是对派生类对象objB中的基类隐含对象的引用AobjA;B&rB=objA;反之不可以!objArB?classA{ intma;public: A(inti):ma(i) {}
int
GetA()const {returnma;}};classB:publicA{ int
mb;public: B(inti,intj) :A(i),mb(j) {}
int
GetB()const {returnmb;}};intmain(){ BobjB(7,8);
A&r=objB;
cout<<r.GetA();
cout<<r.GetB();
return0;}//Error!objBma=7mb=8GetA()GetB()r注意:通过这种引用只能访问派生类对象中的由基类继承来的成员,不能访问派生类中的新增成员。classA{ intma;public: A(inti):ma(i) {}
A(constA&a):ma(a.ma) {}
int
GetA()const {returnma;}};classB:publicA{ int
mb;public:
B(inti,intj) :A(i),mb(j) {}
int
GetB()const {returnmb;}};intmain(){ BobjB(7,8);
AobjA(objB );
cout<<objA.GetA(); return0;}指向基类的指针指向派生类对象3.可以将派生类的对象的地址赋给其基类的指针变量通过这个指针访问派生类中由基类继承来的成员,不能访问派生类中的新增成员。反过来不行。classA{ intma;public: A(inti):ma(i) {}
int
GetA()const {returnma;}};classB:publicA{int
mb;public:
B(inti,intj):A(i),mb(j){}
int
GetB()const{returnmb;}};intmain(){ BobjB(7,8);
cout<<objB.GetA()<<objB.GetB();
A*p=&objB;
cout<<p->GetA();
cout<<p->GetB();
return0;}//Error!概念(补充)概念(补充)对象的静态类型指声明的存在于程序代码文本中的类型。对象的动态类型由它当前所指的对象的类型决定的。举例:A*p=&objB; //p的静态类型为:A* //p的动态类型为:B*
非虚函数是静态绑定的,即,非虚函数的调用取决于对象的静态类型。
注意如:A*p=&objB;p->GetA();p->GetB();//Error!classA{ intma;public: A(inti):ma(i) {}
int
GetA()const {returnma;}};classB:publicA
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 畜牧业设备采购核准表
- 航空会员账户管理办法
- 2025年度水利工程项目承包合伙合同3篇
- 科技园区房产交易合同
- 建筑工程项目担保细则
- 医疗设备招议标管理办法
- 国际石油勘探招投标详解
- 翻译服务业机构装饰施工合同
- 长途客运司机招聘合同样本
- 智能化煤矿配件管理未来趋势
- 天津市西青区2023-2024学年八年级上学期期末数学达标卷(含答案)
- 社会心理学理论考试试题及答案
- 国开2023秋《电子商务概论》实践任务B2B电子商务网站调研报告参考答案
- 国家开放大学《个人理财》形考任务1-4
- 【瑞幸咖啡财务分析报告(附财务报表)5300字(论文)】
- 过敏性鼻炎-疾病研究白皮书
- 三轴水泥搅拌桩施工质量措施
- 幼儿园学前教育五以内的数字比大小练习题
- 垃圾自动分拣机构plc控制毕业论文
- 中国省市行政代码表
- JTG D70-2-2014 公路隧道设计规范 第二册 交通工程与附属设施正式版
评论
0/150
提交评论