c++面向对象程序设计第3章--类和对象

PPT
  • 阅读 105 次
  • 下载 0 次
  • 页数 84 页
  • 大小 356.000 KB
  • 2022-11-12 上传
  • 收藏
  • 违规举报
  • © 版权认领
下载文档30.00 元 加入VIP免费下载
此文档由【小橙橙】提供上传,收益归文档提供者,本网站只提供存储服务。若此文档侵犯了您的版权,欢迎进行违规举报版权认领
c++面向对象程序设计第3章--类和对象
可在后台配置第一页与第二页中间广告代码
c++面向对象程序设计第3章--类和对象
可在后台配置第二页与第三页中间广告代码
c++面向对象程序设计第3章--类和对象
可在后台配置第三页与第四页中间广告代码
c++面向对象程序设计第3章--类和对象
c++面向对象程序设计第3章--类和对象
还剩10页未读,继续阅读
【这是免费文档,您可以免费阅读】
/ 84
  • 收藏
  • 违规举报
  • © 版权认领
下载文档30.00 元 加入VIP免费下载
文本内容

【文档说明】c++面向对象程序设计第3章--类和对象.ppt,共(84)页,356.000 KB,由小橙橙上传

转载请保留链接:https://www.ichengzhen.cn/view-2180.html

以下为本文档部分文字说明:

第3章类和对象本章介绍类与对象的定义、成员函数、构造函数、析构函数、对象与指针等基本概念及应用,讲解C++的继承、重载、多太性等特性,使读者掌握C++的编程基本知识。◼3.1类与对象的定义◼3.2成员函数◼3.3构造函数◼3.4析构函数◼3.5

对象与指针◼3.6类与结构◼3.7继承◼3.8多重继承◼3.9派生类的对象和构造函数◼3.10多态性◼3.11重载◼3.12虚拟函数◼实验3类和对象、继承和派生◼1.类的定义类定义的语法如下:class类名{private:数据成员或成员函数;public:数据成员或成

员函数;protected:数据成员或成员函数;};3.1类与对象的定义类的定义由两大部分组成,即类的数据成员和成员函数。类的数据成员和成员函数也称为类的属性和类的操作。数据成员类似C结构中的变量,成员函数定义了类对数据的操作,反映了类行为和类的能力。例3.1:定

义一个student类,用以描述学生对象。123classStudent{private:charm_Name[20];intm_Age;intm_Sex;charm_cl[20];intm_number;pub

lic:voidRegister(char*Name,intAge,charSex,char*cl,intnumber);voidGetName(char*Name);intGetAge();charG

etSex();voidGetcl(char*cl);intGetnumber();};程序实现:◼2.对象的定义对象是类的实例。从技术上讲,一个对象就是一个具有某种类类型的变量。与普通变量一样,对象也必须先经声

明才可以使用。声明一个对象的一般形式为:<类名><对象1>,<对象2>,…例:StudentStudent1,Student2;声明了两个名为Student1和Student2的Student类的对象。在程序中使

用一个对象,通常是通过对体现对象特征的数据成员的操作实现的。当然,由于封装性的要求,这些操作又是通过对象的成员函数实现的。具体来说:(1)成员函数访问同类中的数据成员,或调用同类中的其他成员函数,可直接使用数据成员名或成员函数名;(2)在对象外访问其数据成员或成员函数

需使用运算符“.”访问对象的成员,例如:number=Student1.Getnumber();(3)不能直接访问一个对象中的私有成员,如果直接访问则导致语法错误;(4)同类对象之间可以整体赋值。例如:Student2=Student

1;(5)对象用作函数的参数时属于赋值调用;函数可以返回一个对象。3.2成员函数在类的定义中仅给出了成员函数的原型,函数的定义还需在其他地方(通常每个类的成员函数的定义放在一起构成一个源程序文件)给出。类的成员函数的一般形式为:<类型><类名>::函数名(<参数表>){‹函数体

›}其中作用域运算符“::”指出成员函数的类属。没有类属的函数称为公共函数。例3.2.1类成员函数的定义。说明:按例3-1说明的方法添加头文件Student.h,输入Student类的定义。然后为项目添加一源代码文件Student.cpp//Example(Stude

nt.cpp):Student类成员函数的定义#include<string.h>#include“Student.h”voidStudent::Register(char*Name,intAge,charSex,cha

r*class,intnumber);{strcpy(m_Name,name);m_Age=age;m_Sex=(sex==’m’?0:1);strcpy((m_cl,cl);m_number=number;}voidStudent::GetName(char*name){strcpy(name,

m_Name);}intStudent::GetAge(){returnm_Age;}charStudent::GetSex(){return(m_Sex==0?‘m’:‘f’):}voidStudent::Getcl(char*cl){strcpy(cl,m_cl);}intStudent::G

etnumber(){returnm_number}例3.2.2定义Student类,并将类Student的成员函数声明为内联函数。clStudent{private:charm_Name[20];int

m_Age;intm_Sex;charm_cl[20];intm_number;public:voidRegister(char*Name,intAge,charSex,char*cl,intnumber){strcpy(m_Name,n

ame);m_Age=age;m_Sex=(sex==’m’?0:1);strcpy((m_cl,cl);m_number=number;}voidGetName(char*Name){strcpy(name,m_Nam

e);}intGetAge(){returnm_Age;}charGetSex(){return(m_Sex==0?‘m’:‘f’);}voidGetcl(char*cl){strcpy(cl,m_cl);}intGetnumber(){returnm_number}

};例3.2.3学生资料的输入输出。//Example:学生资料的输入和输出#include<iostream.h>#voidmain(){voidOutStudentData(Student);charname[20],sex;intage;char

cl[20];intnumber;StudentStudent1,Studen2;cout<<“EnteraStudent’sname、age、sex、cland.number:”;cin>>name>>age>>sex>>cl>>number;Student1.Regist

er(name,age,sex,cl,number);Student2.Register(“Zhang2”,19,’m’,“9901”,100);cout<<“student1:\t”;OutStudentData(Student1);cout<<“Student2:\t”;OutStudent

Data(Student2);Student2=Student1;Cout<<“Student3:\t”;OutStudentData(Student2);}voidOutStudentData(Student);{charname

[20];charcl[20];Student.GetName(name);Student.GetCl(cl)cout<<name<<“\t”<<Student.GetAge()<<“\t”<<Student.GetSex()<<“\t”<<cl<<“\t”<<Student.Getnumber(

)<<end1;}EnteraStudent’sname、age、sex、clandnumber:zhang120’f’“9901”101输入:Student1:zhang120f9901101输出E

nteraStudent’sname、age、sex、clandnumber:zhang219’m’“9902”100输入:Student2:zhang219m9902100输出EnteraStudent’sname、age、sex、clandnumber:zhang320’f’“9901”1

02输入:Student3:zhang320f9901102输出3.3构造函数构造函数是与类名相同的特殊成员函数,当定义对象或者用new动态生成对象时,编译程序将自动调用构造函数以实现对象的初始化。构造函数与普通成员函数的区别,是不允许指定返回类型

,也不返回值。构造函数允许重载。构造函数的声明格式为:<类名>(<参数表>);例3.3.1为类Student增加构造函数。//Example:为类Student增加构造函数#include<string.h>classStudent{

Private:charm_Name[20];intm_Age;intm_Sex;charm_cl[20];intm_number;Public:Student(constchar*name,intage,charsex,constcharcl,intnumber)//构造函数{str

cpy(m_Name,name);m_Age=age;m_Sex=(sex=’m’?0:1);strcpy(m_cl,cl);m_number=number;}voidRegister(char*Name,intAge,charSex,char*cl,intnumber);voidGetName

(char*Name);intGetAge();charGetSex();voidGetcl(char*cl);intGetnumber();};说明:如果在类中没有声明任何构造函数的话,系统会自动地为它定义一个形如<类名>::<类名>()的缺

省构造函数,这种不带任何参数且函数体为空的构造函数就叫做缺省的构造函数。如果在类声明中已经定义了构造函数,则系统不再提供缺省的构造函数。3.4析构函数析构函数的函数名是在类名前加波浪名“~”的特殊成员函数。析构函数与构造函数的功能正好相反;构造函数在对象生成时为其他分配存储空间,而析构

函数的功能是在对象销毁时释放它所占用的内存。析构函数与构造函数一样没有返回值,但它不带参数,不能被重载。析构函数的声明方法为:classExample{public:~Example();//析构函数;};当类的声明中没

有定义析构函数时,C++编译程序会自动产生一个默认的析构函数。。例:#include<iostream.h>classExample{public:Example();~Example();};Example(){cout<

<“Objectiscreated!”<<\\n;}Example::~Example(){cout<<“Objectisdestroyed!”<<endl;}voidmain(){ExampleEx;}Object

iscreated!Objectisdestroyed!执行结果3.5对象与指针可以声明指向对象的指针,方法与声明指向变量的指针相同。例如:StudentStudent1(“Zhang”,19,’f’);Student*ptr=&Student1;通过指针访问对象的成员

要用运算符“->”,例如:Ptr->GetAge();当对象接收到一个消息时,便会调用相应的成员函数。这时,系统会向该成员函数传递一个隐含的参数,即指向该对象自身的指针,即this指针。一般来说,this指针用途不大,因为在成员函数中可以直接使用本对象内部的所有成员变量和成员函数

。但在某些场合中调用其他类的成员函数时,可能需用要传送本对象的地址,在Windows程序设计中这种情况很多,这时就要用到this指针。3.6类与结构C++中有一个结构体类型,其定义和使用方法与类非常相似

。结构体类型的定义方法如下:Struct<结构体类型名>{<结构体类型的成员变量声明语句表>};例:可定义一个表示日期的结构体类型。structdate{intda_year;intda_mon;intda_day;};即一个日期类型的变量有3个成员变量:年份(da

_year)、月份(da_mon)和日(da_day)。在定义好结构体类型以后,就可以定义该类型的变量了:struct<结构体类型名><变量表>;注意在定义时可以略去结构体类型说明符struct,这一点与C语言不同。例:变量声明语句。dateyesterday,today,

tomorrow;声明了3个日期类型的变量:yesterday、today和tomorrow。结构体类型的变量可用作函数的参数或者函数的返回值。对结构体类型变量的成员变量的引用方法与类相同:<结构体类型变量名>.<成员变量名>例:today.da_year=2001;to

day.da_mon=10;today.da_day=10;3.7继承继承性是面向对象程序设计语言的主要特征之一。继承性指的是一个新类可以从现有的类中派生出来,继承该类的特性。被继承的类称为基类(bas

eclass)或父类(parentclass),继承的类称为派生类(derivedclass)或子类(childclass)。继承性允许建立类层次结构,是程序中代码可复用性的关键,并提供对多态性的支持,是C++面向对象程序设计的基石。3.7继承◼1.继承与类层次结构生物动物植物微生物爬行动物哺乳

动物鸟类猫科动物猫图人类认识事物的抽象层次在软件设计中,人们模拟这一过程。在面向对象的程序设计中,继承提供了重用已有代码生成新类的方法。继承在类之间建立了关系。子类可以继承父类的所有数据结构和操作,只要在子类中添加父类没有的数据

结构和操作。在上图中,对象类型CButton是从CWnd派生出来的,CWnd是从CCmdTarget派生出来的,而CCmdTarget又是从CObject派生出来的。CObjectCCmdTargetCByteArrayCCmdTargetCframeWndCDialogCButton

2.派生类的工作方式在C++程序中,当一个类是从一个基类派生出来的时候,该派生类就继承了基类所有的成员变量和成员函数,而且可以加入自己的成员变量和成员函数。但是,基类中声明为私有的成员变量和成员函数是不

可为派生类访问的。基类变量1变量2函数1函数2派生类其他变量其他函数图说明基类和派生类之间的层次关系3.派生一个类声明一个派生类的语法形式为:class派生类名称:继承权限基类名称{┇};其中,继承权限说明符有三种:pub

lic、private和protected,默认权限为private。在类的定义中,所有公有成员都允许其他函数访问,而私有成员则只能供成员函数访问。但是,当派生类继承基类的特性时,派生类无法访问基类中的私有成员。若想让基类中的某些成员不仅可供成员函数访问,而且可将其特性传给派生类,那么

应将其声明为保护类型。例:类继承的例子。#include<iostream.h>classparent//声明基类{inti;//私有成员变量i仅供成员函数使用,不能传递给派生类protected://受保护成员变量仅供成员函数使用,可供派生类使用intx;public://公有

成员,可供任何函数使用parent();voidchange();voidshow();};parent::parent()//定义构造函数{x=0;i=0;}voidparent::change()//定义成员函数{x++;i++;

}voidparent::show()//定义成员函数{cout<<”x=”<<x<<”\n”;}classson:publicparent//声明son为parent的派生类,继承权限为public

,即parent类的//公有成员在son中仍为公有成员,parent类的保护成员在son中仍为//保护成员{public:voidincrease();//声明成员函数};voidson::increase()//定义成员函数体{x++;}保护成员变量x公有成员函数paren

t公有成员函数change公有成员函数increase公有成员函数show经过类继承,派生类son访问以下成员例某公司使用EMPINFO程序管理自己的雇员信息。后来,当该公司在国外开了分支机构而且雇佣不止一个国家的雇员时,如何重新设计EMPINFO程序呢?提示:为了满足跨国公

司的需要,程序设计者从EMPINFO程序中使用的EmpInfo类派生了一个新类,名为OffshoreEmpInfo。#include<iostream.h>classEmpInfo//基类{public:EmpInfo(){}//构造函数和析构函数~EmpInfo(

){}private:char*m_name;char*m_dept;char*m_position;longm_salary;public:voidSetName(char*name){m_name=name;}//设置员变量的值v

oidSetDept(char*dept){m_dept=dept;}voidSetPosition(char*position){m_position=position;}SetSalary(longsalary){m_salary=salary;}voidPrintIn

fo();};classOffshoreEmpInfo:publicEmpInfo//派生类{public:OffshoreEmpInfo(){}//构造函数和析构函数~OffshoreEmpInfo(){}private:char*m_co

untry;public:voidSetCountry(char*country){m_country=country;}voidPintInfo();};voidEmpInfo::PrintInfo(){cout<<”Name:”<<m_nam

e<<”\n”;cout<<”Department:”<<m_dept<<”\n”;cout<<”Position:”<<m_position<<”\n”;cout<<”Salary:”<<m_salary<<”\n”;}voidOffshoreEmpInfo::Prin

tInfo(){EmpInfo::PrintInfo();Cout<<“Country:”<<m_Country<<“\n”;}intmain(){OffshoreEmpInfoempInfo;//定义类OffshoreEmpInfo的对象empInfo.SetName(“PaulNorton”

);empInfo.SetDept(“Development”);empInfo.SetPosition(“Engineer”);empInfo.SetSalary(24000);empInfo.SetCountry(“NewZealand”);e

mpInfo.PrintInfo();return0;}Name:PaulNortonDepartment:DevelopmentPosition:EngineerSalary:24000Country:

NewZealand输出3.8多重继承基类与派生类之间可以有复杂的多对多关系。在类继承中,允许某个类同时继承多个基类,即所谓类的多重继承。在类的多重继承中,基类和派生类间是多对一的关系。基类1基类2基类n……派生类继承

继承继承继承通过多重继承,派生类将继承多个基类的特性,此时基类和派生类的声明方式为:classN1//声明基类N1{┇};┇classNm//声明基类Nm{┇};classS:publicN1,…,publicNm//声明派生类S同时继承基类N1,…,基类Nm{┇};注意:继

承一个以上的基类,要使用逗号分隔的表,还要确保为每个被继承的基类使用一个继承权限说明符。例:两用沙发是一个沙发,也是一张床,两用沙发同时具有沙发和床的特性。程序中类SleeperSofa继承Bed和Sofa两个类。#include<iostream.h>classSofa{protect

ed:intlength;public:Sofa():length(0){}voidSitOn(){cout<<"Sitting...\n";}voidSetLength(inti){length=i;}};classBed{p

rotected:intlength;public:Bed():length(0){}voidSleep(){cout<<"Sleeping...\n";}voidSetLength(inti){length=i;}};classSleepSofa:publicSofa,publicBed//

继承多个基类{public:SleepSofa(){}voidFoldOut()//折叠与打开{cout<<”Folt/Outthesofa.\n”;}};voidmain(){SleepSofasf;sf.SitOn();sf.FoldOut();sf.Sl

eep();}Sitting...Folt/Outthesofa.Sleeping...运行结果3.9派生类的对象和构造函数◼1.派生类的对象用某个基类声明一个派生类后,仍然可以利用基类来声明对象,而且所声明的对象和派生类所声明的对象不会冲突。voidmain(){sonob

1;//用派生类son定义一个对象ob1parentob2;//用基类parent定义一个对象ob2cout<<”Displayderivedclassobjectob1”;ob1.show();//对象o

b1的显示结果ob1.change();//调用从基类中继承的成员函数ob1.increase();//调用派生类中声明的成员函数cout<<”Displaybaseclassobjectob2”;ob2.change();ob2.show

();}Displayderivedclassobjectob1x=0Displaybaseclassobjectob2x=1运行结果◼1.派生类的对象用某个基类声明一个派生类后,仍然可以利用基类来声明对象,而且所声明的对象和派生类所声

明的对象不会冲突。voidmain(){sonob1;//用派生类son定义一个对象ob1parentob2;//用基类parent定义一个对象ob2cout<<”Displayderivedclassobjectob1”;ob1.show();//对象ob1的显示结果ob1.change

();//调用从基类中继承的成员函数ob1.increase();//调用派生类中声明的成员函数cout<<”Displaybaseclassobjectob2”;ob2.change();ob2.show();}Displayderivedclassobjectob1x

=0Displaybaseclassobjectob2x=1运行结果◼2.派生类对象的构造函数和析构函数#include<iostream.h>classbase{public:base(){cout<<”Constructingbase\n”;}~base(){cout<<”Des

tructingbase\n”;}};classderived:publicbase{public:derived(){cout<<”{cout<<”Constructingderived\n”;}~base(){cout<<

”Destructingderived\n”;}};main(){derivedob;//donothingbutconstructanddestructobreturn0;}ConstructingbaseconstructingderivedDestructingderivedDestruct

ingbase运行结果由此可得出一般性的结论:当创建派生类的对象时,如果基类包含构造函数,它将首先执行,派生类的构造函数紧随其后。当撤消派生类的对象时,它的析构函数将首先执行,如果基类包含析构函数,其析构函数将紧随其后。换句

话说,构造函数按其引入的顺序执行,析构函数按其引入的相反顺序执行。在多层继承的情况下(即一个派生类成为另一个派生类的基类),一般规则是,构造函数按引入的顺序执行,析构函数按反序执行。◼3.向基类构造函数传递参数如何向基类的构造函数传递参数呢?答案是使用向一个或多个基类

的构造函数传递参数的派生类构造函数声明的扩展格式即可。这种扩展的派生类构造函数声明的一般格式为:derived_constructor(arg_list):base1(arg_list),base2(arg_list)

,┇baseN(arg_list);{//bodyofderivedconstructor}其中,base1到baseN是派生类继承的基类名。注意,在有多个基类的情况下,用冒号将派生类的构造函数说明和基类分开,用逗号将基类分开。例3.9.2下面的例子使用了多个基类。#inclu

de<iostream.h>classbase1{protected:inti;public:base1(intx){i=x;cout<<”Constructingbase1\n”;}//基类1的有参构造函数~base1(){cout<<”Destructingbase

1\n”;}};classbase2{protected:intk;public:base2(intx){k=x;cout<<”Constructingbase2\n”;}//基类2的有参构造函数~base2(){cout<<

”Destructingbase2\n”;}};classderived:publicbase1,publicbase2{intj;public:derived(intx,inty,intz):base1(y),base2(z)//derived使用x,y,z传递参数给基类构造函数

{j=x;cout<<”Constructingderived\n”;}~derived(){cout<<”Destructingderived\n”;}voidshow(){cout<<i<<””<<j<<””<<

k<<”\n”;}};main(){derivedob(3,4,5);//定义类derived的对象obob.show();//显示435return0;}Constructingbase1Constructingbase2Construct

ingderived435DestructingderivedDestructingbase2Destructingbase1运行结果◼1.多态性(polymorphism)多态性指的是一个接口名称具有多种功

能,是面向对象程序设计的重要特性之一。C++有两种多态性,一是静态的多态性,一是运行时的多态性。所谓静态的多态性,是指操作作用的确切对象是在运行之前(即编译时)就能确定的,所以相应的反应也是在运行之前就能确定的,这种多态性在C++中是用重载实现的。所谓运行时的多态性

,是指操作作用的确切对象依赖于运行的进程,其相应的反应必须在运行时动态给出。C++是通过虚拟函数(virtualfunction)实现这种多态性的。◼2.静态联编与动态联编联编是指将函数调用与相应的函数体代码彼

此关联的过程,若此过程在程序开始运行前的编译阶段完成,称为静态联编。与静态联编不同,在程序运行时进行的联编方式,称为动态联编。一般说来,动态联编是通过指针来实现的。3.10多态性3.11重载◼1.函数重载(1)函数重载及其好处函数重载允许一个程序内声明多个

名称相同的函数,这些函数可以完成不同的功能,并可以带有不同类型、不同数目的参数及返回值。使用函数重载可以减轻用户的记忆负担,并使程序结构简单、易懂。重载包含函数重载和操作符重载,是C++语言提供的一个

重要特性。重载不仅为编译时的多态性提供了大部分支持,而且使得语言具有很大的灵活性和易扩展性。#include<iostream.h>intAbs(inti);doubleAbs(doubled);longAbs(longl);//程序包含三个名为Abs的重载版本的函数main

(){cout<<Abs(-10)<<”\n”;cout<<Abs(-12.0)<<”\n”;cout<<Abs(-7L)<<”\n”;return0;}intAbs(inti){cout<<“usingintegerAbs()\n”;returni<0?-i

:i;}doubleAbs(doubled){cout<<“usingdoubleAbs()\n”;returnd<0.0?-d:d;}longAbs(longl){cout<<“usinglongAbs()\n”;returnl<0?-l

:l;}(2)函数重载的基本规则重载函数时我们必须遵守一个基本规则:你提供给编译程序的重载函数必须在它们的参数类型或参数数量上不同。#include<iostream.h>intmyfunc(inti);intmyfunc(inti,intj);//重载函数具有不同数目的参数main(){

cout<<myfunc(20)<<”\n”;//调用myfunc(inti)cout<<myfunc(3,4)<<”\n”;//调用myfunc(inti,intj)return0;}intmyfunc(inti){returni;}intmyfu

nc(inti,intj){returni*j;}(3)重载成员函数在类的成员函数和构造函数上,也可以直接使用函数重载的概念。例如,假设你要写两个不同的函数来显示一个窗口,一个函数要求提供大小作为一个参数,另一个不要求参数但使

用缺省尺寸。可以以这种形式写一对重载的成员函数:voidDisplayWindow();voidDisplayWindow(CRectwinRect);创建完这些重载的成员函数之后,就可以调用任意一个。这个语句将调用第一个DisplayWindow函数:DisplayWindow()

;下面的语句将调用第二个DisplayWindow函数:CRECTwinRect(10,10,50,200);DisplayWindow(winRect);(4)重载构造函数在C++中,构造函数经常被重载。许多构造函数有两个甚至更多的版本。classExample

{intx;public:Example(){x=0;}//定义重载的构造函数Example(inta){x=a;}voiddisplay();};┇定义重载的构造函数后,声明对象时就可以根据不同的参数来分别调用不同的构造函数。例如:voidmain(){Examp

leA;//自动调用构造函数Example()ExampleB(3);//自动调用构造函数Example(inta)┇(4)重载构造函数在C++中,构造函数经常被重载。许多构造函数有两个甚至更多的版本。classExamp

le{intx;public:Example(){x=0;}//定义重载的构造函数Example(inta){x=a;}voiddisplay();};┇定义重载的构造函数后,声明对象时就可以根据不同的参数来分别调用不同的构造函数。voidmain(){ExampleA;//自

动调用构造函数Example()ExampleB(3);//自动调用构造函数Example(inta)┇}例:下面的程序创建了一个叫做date的类,它表示一个公历日期。#include<iostream.h>#include<stdio.h>classdate{intday,month,year;

public:date(char*d);date(intm,intd,inty);voidshow_date();};date::date(char*d)//用字符串初始化{sscanf(d,”%d%*c%

d%*c%d”,&month,&day,&year);}date::date(intm,intd,inty)//用整数初始化{day=d;month=m;year=y;}voiddate::show_date()

{cout<<month<<”/”<<day;cout<<”/”<<year<<”\n”;}main(){dateob1(3,6,2000),ob2(”10/21/1999”);ob1.show_date();ob2.show_date();return0

;}(5)派生类中的重载函数在类继承中,也可以出现基类的成员函数和派生类的成员函数名字相同的情形。这时,在派生类中说明的任何重载超越在基类中说明的函数。#include<iostream.h>classAclass{private:intaVal;public:Ac

lass(){}~Aclass(){}intValue(intn){aVal=n+1;returnaVal;}};classBclass{private:floatbVal;public:intValue(floatn){bVal=n+2;returnbVal;}

};intmain(){Bclassanob;cout<<anob.Value(100)<<’\n’;return0;}上例中,名为Bclass的类从Aclass类中派生出来。Aclass的定义中包含了一个名为Value的函数。(6)作用域操作符如果由派生类说明的成员函数超越

了由基类说明的成员函数,那么可以用作用域操作符(::)的指引来访问在基类中说明的成员函数。例:可以用下面的main()函数来代替上例中的main()函数。intmain(){Bclassanobject;cout

<<anobject.Aclass::Value(100)<<’\n’;//使用作用域操作符来调用Aclass::Value()return0;}101运行结果◼2.操作符重载操作符重载和函数重载功能一致。通过操作符重载,可以重新定义C++语言中的已有操作符的功能,使得它们能针对不同的情

况执行不同的操作。操作符重载使得程序员可把C++操作符的定义扩展到操作数是对象的情况。(1)编写操作符重载函数函数类型operator#(形参表){//函数体}其中,operator是关键字(所以有时也称操作符重载函数为operator函数),#表示欲定义的操作符,函数类型

指明返回值类型,通常与类类型一致或为void类型。(2)操作符重载函数的作用域当重载一个操作符时,普通的作用域规则也适用,操作符被重载的作用范围就是重载它的函数出现的作用范围。Moneyoperator+(int){//函数体}(3)C

++如何实现操作符重载①在C++语言中,操作符只能对属于固有类型的常量和变量进行操作。而且,C语言中操作符的含义是固定的。②在C++中你可以根据自己的意图定义操作符。当你重定义一个操作符时,你可以用代码记号来

表达对用户自定义类的操作。③当C++编译程序对一个表达式进行求值时,它会检查一系列的与操作符号混在一起的值(包括常量和变量)。当遇到一个操作符时,它首先判断此操作符是用作一元或者是二元操作符。然后,编译程序根据优先规则和组织规则对此表达式求值,同时根据这些规则要求给操作符和操作数分组。④

编译程序判定它遇到的操作符的操作数据的类型。只有在那时,它才知道此表达式是否合法,而且如果合法,则应当产生什么代码。例:重载一元操作符++,用来递增Money类的值。例中Money类用来存放钱数,它包含两个双精度的成员变量。一

个成员变量用于存储结果的元值,另一个用于存储结果的分值。#include<iostream.h>#include<math.h>#include<stdlib.h>#include<stdio.h>cl

assMoney{private:doubledollars;doublecents;public:Money(){}//定义构造函数~Money(){}//定义析构函数Money(doubled,doublec);//另一构造函数Money(double);//从d

ouble转换Moneyoperator++();//操作符重载doubleGetAmount(double&n);};MoneyMoney::operator++(){cents++;if(cents>99){dollars++;cents=0;}return*this;}Mone

y::Money(doubled,doublec){dollars=d;cents=c;}Money::Money(doublecash)//一个转换构造函数{//将浮点值转换成Money值doublefrac,n;f

rac=modf(cash,&n);//一个math.h函数cents=frac*100;dollars=n;}doubleMoney::GetAmount(double&n){n=dollars;returncents;}intmain(){doublec,d;Mo

neymyCash(7.99);c=myCash.GetAmount(d);cout<<d<<"dollars\n";cout<<c<<"cents\n";++myCash;c=myCash.GetAmount(d);cout<<d<<"dollars\n";cout<<

c<<"cents\n";return0;}7dollars99cents8dollars0cents运行结果例:重载加法操作符,使其将两个Money类的值相加并将结果存在一个Money对象中。#include<iostream.h>#inclu

de<math.h>#include<stdlib.h>classMoney{private:doubledollars;doublecents;public:Money(){}//定义构造函数~Money(){

}//定义析构函数Money(doubled,doublec);//另一构造函数Money(double);//转换构造函数Moneyoperator+(Moneym);//操作符重载doubleGetAmount(double&n);};MoneyMoney::ope

rator+(Moneym){cents+=m.cents;dollars+=m.dollars;if(cents>99){dollars=dollars+1;cents=cents-100;}return*this;}Money::Money(doub

led,doublec){dollars=d;cents=c;}Money::Money(doublecash)//一个转换构造函数{//将浮点值转换成Money值doublefrac,n;frac=modf(cash,&n);//一个math.h函数cents=frac*100;dol

lars=n;}doubleMoney::GetAmount(double&n){n=dollars;returncents;}intmain(){doublec,d;MoneymyCash(3.49);MoneyyourCash(50.86);myCash=myCas

h+yourCash;c=myCash.GetAmount(d);cout<<"Younowhave"<<d<<"dollars.\n";cout<<"Youalsohave"<<c<<"cents.\n";return0;}Younowha

ve54dollars.Youalsohave35cents.运行结果◼1.多态性与虚拟函数C++的多态性是通过虚拟函数来实现的,而虚拟函数是基于继承的环境中。在继承关系下,派生类作为基类的子类,在任何要求

基类对象的地方使用派生类对象是有意义的。我们可以用基类指针通过间接或直接的方式指向它的任何派生类的对象。当通过一个基类指针引用一个派生类对象时,只能调用基类所定义的成员函数,而无法调用派生类定义的成员函数,即使派生类重新定义了基类的成员函数,所调用的仍是基类

中的而不是派生类中的成员函数。当通过指针引用一个对象时,指针的类型决定了可以调用的成员函数。3.12虚拟函数#include<iostream.h>classPerson{public:voidDisplay(){cout<<“classPe

rson\n”;}};classChild:publicPerson{public:voidDisplay(){cout<<”classChild\n”;}};classOld:publicPerson{public:voidDisplay(){cout<<”classold\n”

;}};voidmain(){Personpeople1;Person*p;Childpeople2;Oldpeople3;p=&people1;p->Display();p=&people2;p->Display();p=&people3;p->Dis

play();}classPersonclassPersonclassPerson运行结果修改上面的例子,将基类的成员函数Display()声明为虚拟函数。#include<iostream.h>classPerson{public:virtualvoidDispl

ay()//声明基类的成员函数为虚拟函数{cout<<“classPerson\n”;}};//定义基类PersonclassChild:publicPerson{public:voidDisplay(){cout<<”classChild\n”;}};//定

义派生类ChildclassOld:publicPerson{public:voidDisplay(){cout<<”classold\n”;}};//定义派生类Oldvoidmain(){Personpeople1;Person*

p;//定义基类指针pChildpeople2;Oldpeople3;p=&people1;//基类指针指向基类对象people1p->Display();//调用基类Person的成员函数Display()p=&people2;

//基类指针指向基类对象people2p->Display();//调用派生类Child的成员函数Display()p=&people3;//基类指针指向基类对象people3p->Display();

//调用派生类Old的成员函数Display()}classPersonclassChildclassOld运行结果基类用虚拟函数提供一个派生类对象都具有的共同界面,派生类又各自对虚拟函数定义自己的具体实现。若派生类中没有重新定义基类的虚拟函数,则该派生类直接继承其基类的虚拟函数。当一

个函数在基类被声明为虚拟函数后,不仅可与其直接派生类形成虚拟关系,与其间接派生类也可以形成虚拟关系,不管经历了多少层派生,都将保持其虚拟性。类Avirtualvoiddisplay()类Bvirtualvoiddisplay()类Cvirtualvoiddisplay(

)基类第一层派生类继承第二层派生类继承voidmain(){A*pp;//声明一个指向类A的指针ppAm;//声明类A的对象mBn;//声明类B的对象nCp;//声明类C的对象ppp=&m;//指针pp指向A类对象pp->Display()

;//调用基类A中的成员函数display()pp=&n;//指针pp指向派生类B对象pp->Display();//调用派生类B的成员函数display()pp=&p;//指针pp指向派生类C对象pp->Display();//调用派生类C中的成员

函数display()}在基类A中声明了虚拟函数display,这种虚拟特性被继承到类B和C中,使用时就可以实现多态性。程序实现:◼2.纯虚拟函数实际应用中,C++语言设计虚拟函数时通常都是用基类定义某事件的接口和数据,而在派生类中定义处理该事件的方法,这样就可以实现单一接口,

多种功能。由于在基类中定义的虚拟函数通常只是完成初始化或定义接口的目的,一般不执行具体功能,所以为了减小程序的复杂程度并节省内存空间,可以让此函数等于零,称为纯虚拟函数。纯虚拟函数的声明形式如下:virtual函数原型=0;将虚拟函数的原型设置为0,该虚拟函数即为纯虚拟函数。3.12虚拟函数#in

clude<iostream.h>classBaseC//声明基类BaseC{protected://声明保护类型的数据,可被派生类继承intx;public:virtualvoidinit_value(inti)//该虚拟函数用于初始化{x=i;}virtualvoiddisplay()

=0;//该函数被声明为纯虚拟函数。当各派//生类中均未定义display()虚拟函数时,//则执行此虚拟函数};classSquareC:publicBaseC//声明派生类SquareC{public:voiddisplay()//派生类中的虚拟函数display{

cout<<”X=”<<x<<endl;cout<<”XSquare=”<<x*x<<endl;}};classCubeC:publicBaseC//声明派生类CubeC{public:voiddisplay()//派生类

中的虚拟函数display{cout<<”X=”<<x<<endl;cout<<”XCube=”<<x*x*x<<endl;}};voidmain(){BaseC*pp;//声明指向类BaseC的指针ppSquareCA;//声明类SquareC的对

象ACubeCB;//声明类CubeC的对象Bpp=&A;//指针pp指向派生类SquareCpp->init_value(2);//尽管派生类SquareC中未声明虚拟函数init_value,但程序执行时将自动寻找所//属基类BaseC中的虚拟函数/

/init_value,并执行它pp->display();//调用派生类SquareC中的虚拟函数displaypp=&B;//指针pp指向派生类CubeCpp->init_value(4);//指针pp自动寻找所属的基类BaseC,执行所声//明的虚

拟函数init_valuepp->display();//调用派生类CubeC中的虚拟函数display}X=2XSquare=4X=4XCube=64运行结果实验3类和对象、继承和派生实验目的和要求1.掌握类和对象的定义和使用方法。

2.掌握定义构造函数和析构函数、重载构造函数的方法。3.掌握静态成员和常类型的用法。4.掌握继承和派生类的方法。5.正确理解public,private和protected三种访问权限及继承方式的区别。6

.掌握在派生类中初始化基类成员的方法。实验内容编写程序:定义一个人类Cperson,包括数据成员:姓名,编号,性别和用于输入输出的成员函数。在此基础上派生出学生类Cstudent(增加成绩)和教师类Cteacher(增加教龄)并实现对学生信息和教师信息的输入输出。实验步骤1.启动Vi

sualC++6.02.建立控制台应用程序并输入代码3.完成工程项目的编译,运行。4.写出实验报告。◼参考代码#include<string.h>#include<iostream.h>classcperson{public:cp

erson(){strcpy(pname,””);strcpy(pid,””);}cperson(char*name,char*id,boolisman=1){input(name,id,isman);}voidinput(char*name,char*id,boolisman){setn

ame(name);setid(id);setsex(isman);}Voidoutput(){cout<<”姓名:”<<pName<<endl;cout<<”编号:”<<pID<<endl;char*str=bMan?”男”:”女”;cout<<”性别:”<<str<<endl;}public:

//姓名属性操作Char*getName()const{return(char*)pName;}voidsetName(char*name){intn=strlen(name);strncpy(pName,name,n);pName[n]=’

\0’;}//编号属性操作Char*getID()const{return(char*)pID;}voidsetID(char*id){intn=strlen(id);strncpy(ID,id,n);pId[n]=’/0’;}//性别属性操作boolg

etSex(){returnbMan;}voidsetSex(boolisman){bMan=isman;}Private:charpName[20];//姓名charpID[20];//编号boolbMan;//性别:0表示女,1表示男}classCstudent:publicC

person{public:Cstudent(char*name,char*id,boolisman=1);~Cstudent(){}voidInputScore(doublescore1,doublescore2,doublescore

3);voidPrint();Cpersonsudentprivate:doubledbScore[3];//3门成绩};classCteacher(char*name,char*id,boolisman=1

,intyears=10);~Cteacher(){}voidprint();privte:intnTeachYears;//教龄};#include<octream.h>#include”Ex_Class.h”//类Cstudent实现代码Csudent::Cstudent(char*na

me,char*id,boolisman)Sudent(name,id,isman){dbScore[0]=0;dbScore[1]=0;dbScore[2]=0;}voidCstudent::InputScore(doublescore,doublescore2,

doublescore3){dbSorce[0]=score1;dbSorce[1]=score2;dbSorce[2]=score3;}voidCstudent::Print(){student.Output()for(intI=0;I<3;I++)cout<<”成绩”<<I+1<<”:

”<<dbScore[i]<<endl;}//类Cteacher实现代码Cteacher::Cteacher(char*name,char*id,boolisman,intyears{nTeachYears=years;Input(name,id,isman);

}voidCteacher::Print(){Output()cout<<”教龄:”<<nTeachYears<<endl;}//主函数voidmain(){Cstudentstu(“LiMing”,”210110211”);C

out<<stu.getName()<<endl;stu.Print();stu.student.setName(LingLing”);stu.studentsetSex(0);stustudentsetSex(0);

stu..InputScore(80,90,85);stuPrint();Cteachertea(“Ding”,”911085”);tea.Print()tea.setID(“9110234”),tea.Print()}思考与练习1.定义一个用于描述人的属性的类并定义获取信息的成

员函数。2.为一个小型的图书馆的管理系统定义图书卡类、借书证类和借书纪录类,设计其成员函数,包括书卡录入函数和借书证录入函数、借书证等击函数和还书处理函数。设计好的类可自主函数验证。3.设计一个基类base,包括编号、姓名、住址以及相关的成员函数,由它派生

出学生类student和教师类teacher,并用一些数据进行测试。4.创建一个person类,属性包括姓名、性别、出生日期。然后从person类派生出一个教师类,新增加的属性有:专业、职称和主讲课程(一门)。并要求定义相应的设置属性的成员函数和输出信息的成员函

数。5.在类定义中使用protected关键字的目的是什么?6.圆和三角形都需要输入三个数据,设计一个类object管理这三个数据,从此派生出圆类circle和三角类triangle,并求出各自的面积。7.派生一个新类时继承权限public,private和protected有何区别?8.编写一

个程序,设计一个base(基类),它有两个私有数据成员(x和y)以及一个虚函数add(),由它派生出two类和three类,后者添加一个私有数据成员z,在这些派生类中实现add()成员函数。并用数据进行测试

。思考与练习9.编写一个程序,实现对文具销售情况管理。当输入一系列文具纪录后,将销售良好的(该类文具销售额在2万元以上)的文具名称显示出来。10.设计一个学生类student,包括姓名和三门课程成绩,利用重载运算符“+”将所有学生的成绩相加放在一个对

象中,再对该对象求各门成绩的平均分。11.设计一个时间类time,包括时、分、秒等私有数据成员。要求实现时间的基本运算,如一时间加上另一个时间,一个时间减去另一个时间。12.设计并实现一个简单的类,然后从这个基类派生出一个新类,至少要重载一个继承的成员函数。13

.编写一个小型公司人员管理程序,要求存储公司人员的编号、姓名、级别和月薪。该公司主要有四类人员:经理、兼职技术人员、销售经理和销售员。不同人员月薪的计算方法为:经理固定为月薪8000元;兼职技术人员按照每小时100元领取月薪;销售人员按当月销售额的5%提成;销售经

理月薪为固定的5000元加销售额的0.5%。

小橙橙
小橙橙
文档分享,欢迎浏览!
  • 文档 25747
  • 被下载 7
  • 被收藏 0
相关资源
广告代码123
若发现您的权益受到侵害,请立即联系客服,我们会尽快为您处理。侵权客服QQ:395972555 (支持时间:9:00-21:00) 公众号
Powered by 太赞文库
×
确认删除?