Download presentation
Presentation is loading. Please wait.
Published byIndra Santoso Modified 6年之前
1
第六章 面向对象程序设计基础 6.1 面向对象程序设计概述 6.2 结构 6.3 类和对象 6.4 继承和派生 6.5多态性
第六章 面向对象程序设计基础 6.1 面向对象程序设计概述 6.2 结构 6.3 类和对象 6.4 继承和派生 6.5多态性 6.6 程序举例
2
Object Oriented Programming
6.1 面向对象程序设计(OOP)概述 Object Oriented Programming 基本概念 对象:现实世界的实体,每个对象都有所属的类 类: 对一组对象共同具有的属性和行为的抽象, 具有封装和隐藏性、还具有继承性。 消息:向某对象请求服务的一种表达方式,是对 象与外界、对象与其它对象之间联系的工具 方法:对某对象接受消息后所采取的操作的描述。
3
特点 封装性 继承性 多态性 C++中,通过类和对象实现对数据的封装,使得程序的修改维护更方便。是OOP的基础。
4
C++中的类从C语言中的结构概念演变而来
6.2 结构 C++中的类从C语言中的结构概念演变而来 结构类型说明形式 struct 结构类型标识符 { 结构成员1; 结构成员2; ┆ 结构成员n; }; 说明结 构类型 的关键字 类型可任意 (不能为该结构自身)
5
如,说明一个结构类型date,含三个整型数据成员
struct man { char name[15]; char sex; int age; date birthday; }; struct date { int month; int day; int year; }; 在此基础上,又可说明另一个结构类型man birthday Name sex age month day year struct man 结构类型
6
结构变量定义 先说明结构类型再定义结构变量 在说明结构数据类型的同时定义结构变量 省略结构标识符直接定义结构类型变量 无类型名变量
struct man man1, man2; 先说明结构类型再定义结构变量 在说明结构数据类型的同时定义结构变量 省略结构标识符直接定义结构类型变量 struct { char name[15]; char sex; int age; struct date birthday; } man1, man2; struct man { char name[15]; char sex; int age; struct date birthday; } man1, man2; 无类型名变量
7
括号不能少 通过指向结构的指针引用结构变量成员
结构变量的引用 成员访问运算符 优先级最高的 四个运算符之一 形式: 结构变量名.成员名 (*指向结构的指针).成员名 指向结构的指针->成员名 或 或 括号不能少 通过指向结构的指针引用结构变量成员 如,假设有定义 man m,*p=&m; 则可如下引用结构成员 strcpy (m.name, "Fang Min"); p->birthday.month = 8;
8
6.3 类和对象 [引例]定义一有关职工工资信息的结构类型,对某职工的该类信息进行处理。职工信息包括姓名、基本工资、岗位工资和职务工资;对该类信息的处理包括输入、输出和求总收入情况。 #include "iostream.h" struct stuff {char name[10]; double jw,gw,zw; }s ; void print( ) {cout<<s.name<<":"<<s.jw<<'\t'<<s.gw<<'\t'<<s.zw<<endl;} void input( ) {cin>>s.name>>s.jw>>s.gw>>s.zw;} double salary( ) {double sum=0; sum=sum+s.jw+s.gw+s.zw; return sum; } void main() {input( ); print( ); cout<<salary( ); 结构化的方法
9
结构化程序的框架 结构化程序
10
以面向对象的方式实现 #include "iostream.h" class stuff {private: char name[10]; double jw,gw,zw; public: void print( ) {cout<<name<<":"<<jw<<'\t'<<gw<<'\t'<<zw<<endl;} void input( ) {cin>>name>>jw>>gw>>zw;} }; double salary( ) {double sum=0; sum=sum+jw+gw+zw; return sum; } void main() {stuff s; s.input( ); s.print( ); cout<<s.salary( );
12
6.3.1 类的定义 类是一种复杂的数据类型,它是将不同类型的数据和与这些数据相关的运算封装在一起的集合体, 定义格式: class 类名
{public: <成员函数或数据成员的说明>; private: protected: }; <各成员函数的实现>
13
定义包括说明部分和实现部分。若成员函数在说明部分已定义,则实现部分可省略;若成员函数在类体外实现,需用类名和作用域运算符(::)标识所属类。
说明: 定义包括说明部分和实现部分。若成员函数在说明部分已定义,则实现部分可省略;若成员函数在类体外实现,需用类名和作用域运算符(::)标识所属类。 访问权限修饰符:public(公有)、private(私有 )和 protected(保护) 缺省时为private。 公有成员通常为成员函数,可在程序中引用,私有成员通常是数据成员,只有成员函数或友元函数才可引用。 类体中不允许对数据成员初始化。 class B {private: int year=2002, month=10, day=12; …… }; 错
14
[例6-1]:定义一个Circle类(圆类),包括如下的一些数据成员
和成员函数. 数据成员 成员函数 名称 含义 功能 x 圆心坐标x值 set 设置数据成员值 y 圆心坐标y值 print 输出数据成员值 r 圆半径 area 求圆的面积 求圆的周长 lenth
15
class Circle {private: double x,y,r; public: void print( ); void set(double x1,double y1,double r1); double area( ) {return (3.14*r*r);} double lenth() {return(2*3.14*r);} }; void Circle::print() {cout<<"圆心:("<<x<<","<<y<<")"<<endl; cout<<"半径:"<<r<<endl; } void Circle:: set(double x1,double y1,double r1) { x=x1; y=y1; r=r1;}
16
6.3.2 对象的定义 格式: 如,假设A是一个已定义过的类,则可定义: 类名 对象名表;
类名仅提供一种类型定义,只有在定义属于类的变量后,系统才会为其预留空间,这种变量称为对象,它是类的实例。 格式: 如,假设A是一个已定义过的类,则可定义: 类名 对象名表; A a1,*p,a[5] A类的对象 对象数组 指向A类对象的指针
17
类成员的访问方式 对象名.成员名 对象指针名->成员名 类内: (成员函数访问数据成员) 直接访问类成员
类内: (成员函数访问数据成员) 直接访问类成员 类外: (外部程序访问类的成员函数) 访问方式同结构成员,具体如下: 对象名.成员名 对象指针名->成员名
18
[例6-2]编制主函数,通过例6-1中定义的Circle类,对圆心在原点,半径为2的圆和圆心在点(1,1)上,半径为4的圆进行测试。
void main() { Cirlce p1,*p2; p1.set(0,0,1); p1.print( ); cout<<p1.area<<‘\t’<<p1.lenth<<endl; p2=new Circle; p2->set(1,1,4); p2->print( ); cout<<p2->area<<‘\t’<<p2->lenth<<endl; }
19
6.3.3 对象的初始化 1.构造函数和析构函数 [例6-3] 看例6-2的另一种实现 class Circle {private:
double x,y,r; public: void print( ); Circle(double x1,double y1,double r1); double area( ) {return (3.14*r*r);} double lenth() {return(2*3.14*r);} }; Circle::Circle(double x1,double y1,double r1) { x=x1; y=y1; r=r1;} //其它函数实现略 void main() { Circle p (0,0,2); p.print(); …… } 1.定义的同时初始化对象 2.省略对赋初值成员函数的额外调用
20
构造函数特点 是成员函数,可写在类体内,亦可写在类体外。 函数名同类名,不能指定函数类型,可以带参数。
析构函数特点: 是成员函数,可写在类体内,亦可写在类体外。 函数名同类名,不能指定函数类型,可以带参数。 可重载,即可定义多个参数个数不同的函数。 在创建对象时由系统自动调用,程序中不能直接调用。 是成员函数,可写在类体内,亦可写在类体外。 函数名同类名,前面多个字符“~” ,不指定类型,无参。 不可重载,即一个类只能定义一个析构函数。 可被调用,也可由系统调用。系统自动调用情况如下: 若一个对象被定义在函数体内,则当该函数结束时, 该对象的析构函数被自动调用。 当一个对象是使用new运算符被动态创建的,在使用delete释放时,析构函数将会被自动调用
21
<类名>::<缺省构造函数名>( ) <类名>::~<缺省析构函数名>()
2.缺省构造函数和缺省析构函数 形式: 说明: 若没有定义任何构造函数,系统会自动生成上述无参的缺省构造函数及析构函数 若定义一个静态对象而没有指明初始化时,编译器会按缺省构造函数对对象的所有数据成员都初始化为0或空。 <类名>::<缺省构造函数名>( ) { } <类名>::~<缺省析构函数名>() { }
22
[例6.3] 定义一个Circle1类,具有求一个圆的面积、求两个圆的面积之和,以及输出面积等功能 。
#include "iostream.h" class Circle1 {private: double x,y,r,s; public: void print() {cout<<"圆心:("<<x<<","<<y<<")"<<endl; cout<<"半径:"<<r<<endl; } Circle1() { } Circle1(double x1,double y1,double r1) { x=x1; y=y1; r=r1;} void addarea(Circle1 p1,Circle1 p2) {s=3.14*(p1.r*p1.r)+3.14*(p2.r*p2.r);} void disp() { cout<<"面积:"<<s<<endl;} }; void main() { Circle1 p1(0,0,2),p2(1,1,4),p3; p1.print(); p2.print(); p3.addarea(p1,p2); p3.disp(); } 初始化了吗 可缺省吗?验证一下
23
[例6.4] 析构函数示例 析构函数中输出处理结果(未设专门输出函数) #include <iostream.h>
[例6.4] 析构函数示例 析构函数中输出处理结果(未设专门输出函数) #include <iostream.h> #include <conio.h> class count {int num; public: count(); ~count(); void process(); }; count::count() {num=0;} count::~count() {cout<<"字符个数:"<<num<<endl;} void count::process() {while(cin.get()!='\n') num++; cout<<endl; } void main() {count c; cout<<"输入一个句子:" ; c.process(); } 析构函数在程序结束 前由系统自动调用
24
3.拷贝初始化构造函数 用于用已知对象初始化被创建的同类对象 只有一个参数,且是对某个对象的引用 [例6.5] 常用于做函数的形参及返回值
拷贝初始化构造函数(引用做参数) #include "iostream.h" class Circle1 { private: double x,y,r,s; public: void print() {cout<<"圆心:("<<x<<","<<y<<")"<<endl; cout<<"半径:"<<r<<endl; } Circle1(double x1,double y1,double r1) { x=x1; y=y1; r=r1;} Circle1( Circle1 &p) {x=p.x; y=p.y, r=p.r;} }; void main() {Circle1 p1(0,0,2),p2(p1); p1.print(); p2.print(); } 已知对象做初值
25
6.3.4常对象和常成员 1.常成员函数 形式: 类型说明符 函数名(参数表) const 说明:
只有常成员函数可以操作常对象 [例6.6]常成员函数示例
26
不修改数据成员,定义为常函数 前面的解释符可去掉吗
#include "iostream.h" class Time {private: int hour,minute,second; public: Time::Time() { } Time::Time(int h,int m,int s) {hour=h; minute=m; second=s;} void settime(int h,int m,int s) void print()const {cout<<hour<<":"<<minute<<":"<<second<<endl;} }; void main() {Time t1; const Time t2(10,23,34);//定义t2为常对象 t1.settime(11,15,20); t1.print(); //t2.settime(4,12,15); t2.print(); } settime函数可声明为const吗 不修改数据成员,定义为常函数 前面的解释符可去掉吗
27
2.常数据成员 对不应该被修改的数据成员声明为const,可使其受到强制保护,初始化方式与一般数据成员不同。 初始化列表的方式初始化
class Decrement { private: int num; const int dec; //将dec声明为常数据成员 public: Decrement(int n,int d):dec(d) { num=n;} void fdec() {num=num-dec; } void print()const {cout<<"num="<<num<<",dec="<<dec<<endl; } }; 初始化列表的方式初始化
28
6.3.5静态成员 1。静态数据成员 初始化格式: 是类的成员,被所有对象所共享,在内存中只存贮一次 定义或说明时前面加关键字static
静态成员的提出是为了解决数据共享的问题,它比全局变量在实现数据共享时更为安全,是实现同类多个对象数据共享的好方法。在类中,分为静态数据成员和静态函数。 1。静态数据成员 初始化格式: 是类的成员,被所有对象所共享,在内存中只存贮一次 定义或说明时前面加关键字static 初始化在类外进行,不加static和访问权限修饰符 数据类型 类名::静态数据成员=值
29
通过以下程序了解静态数据成员的声明、初始化的位置和限定及具有类对象共享的属性。
[例6.7] 静态数据成员示例程序 通过以下程序了解静态数据成员的声明、初始化的位置和限定及具有类对象共享的属性。 创建A时 k值0->1 创建B时 k值1->2。 void main() { Tc A,B; A.display(); B.display(); } 运行结果: #include <iostream.h> class Tc {private: int i; static int k; public: Tc( ) {i=0; i++; k++;} void display() { cout<<i<<","<<k; } }; int Tc::k=0; 静态变量声明 1,2 静态变量初始化
30
2.静态成员函数 类名::静态成员函数名(参数表) 调用形式: 静态成员函数是类的成员函数,而非对象的成员。
静态成员函数中数据成员的引用也有区别: [例6.8]静态成员函数应用程序示例 静态成员函数是类的成员函数,而非对象的成员。 类名::静态成员函数名(参数表) 对静态数据成员,直接引用 对非静态数据成员,通过对象引用
31
#include <iostream.h> class Tc {private: int A; static int B;
public: Tc(int a) {A=a; B+=a;} static void display(Tc C) { cout<<C.A<<B; } }; int Tc::B=2; void main() { Tc A(2),B(4); Tc::display(A); Tc::display(B); } 静态成员函数的调用 静态数据成员的引用 非静态数据成员的引用 通过该程序了解程序中静态成员函数的调用方式以及静态成员函数中静态数据成员和非静态数据成员的引用方式
32
6.3.6 友元函数 为非成员函数 可访问类中私有成员 [例6.9]友元函数示例程序 说明时前面加关键字friend标识
void Cpoint::print() { cout<<X<<Y ; } double dist(Cpoint &a,Cpoint &b) int dx=a.X-b.X; int dy=a.Y-b.Y; return sqrt(dx*dx+dy*dy); void main() {Cpoint p1(3,4),p2(6,8); p1.print(); p2.print(); double d=dist(p1,p2); /*友元不是成员函数不需对象表示,直接调用*/ cout<<"Distance is "<<d<<endl; 前不能加 friend #include <iostream.h> #include <math.h> class Cpoint {private: int X,Y; public: Cpoint(int x, int y) { X=x; Y=y; } void print(); friend double dist(Cpoint &a,Cpoint &b); }; 友元函数说明
33
6.4 继承和派生 基类(父类) 单继承 派生类 (子类) 多继承 计算机系人员 学生 研究生 本科生 系主任 行政管理人员 教务 教师
6.4 继承和派生 基类(父类) 计算机系人员 学生 研究生 本科生 系主任 行政管理人员 教务 教师 教职工 单继承 派生类 (子类) 多继承
34
从Circle类中派生而来 对比如下两个圆柱体类的定义 全部数据成员重新定义 只定义一个新成员(Circle中没有)
class Cylinder {private: double x,y,r,h; public: void print() { cout<<"圆心:("<<x<<", " <<y<<")"<<endl; cout<<"半径:"<<r <<",圆柱高:"<<h<<endl; } void set(double x1,double y1, double r1,double h1) { x=x1; y=y1; r=r1; h=h1;} }; 全部数据成员重新定义 class Cylinder1:public Circle {private: double h; public: void print() {Circle::print(); cout<<"圆柱高:"<<h<<endl; } void set(double x1,double y1, double r1,double h1) { Circle::set(x1,y1,r1); h=h1; }; 只定义一个新成员(Circle中没有) 通过调用Circle类成员函数输出Circle类成员
35
6.4.2单继承 1.派生类的定义格式 class 派生类名: 继承方式 基类名 { 派生类新定义成员};
public(公有基类) private(私有基类) protected(保护基类) class 派生类名: 继承方式 基类名 { 派生类新定义成员}; 若要在派生类Cylinder1中再增加一个成员函数volume,用以求圆柱体的体积,则该成员函数能否如下实现: 原有类(父类) 错! double Cylinder1::volume() {return(3.14*r*r*h);} r是Circle类的私有成员, 不能被派生类访问
36
2.继承方式 public,private和 protected 是三种常用的继承方式,继承方式的不同决定了派生类对基类成员的访问权限不同。
派生类的继承关系 基类 私有成员 (private) 公有成员 (public) 保护成员 (protected) 私有派生类 不可访问的成员 公有派生类 保护派生类(protected)
37
[例6.10]分析下列程序中的访问权限,并回答所提的问题。
#include <iostream.h> class A {public: void f1(); A( ) {i1=10;j1=11;} protected: int j1; private: int i1; }; class B:public A void f2( ); B( ) {i2=20;j2=21;} int j2; int i2; class C:public B {public: void f3(); C( ) {i3=30;j3=31;} protected: int j3; private: int i3; }; void main() {A a; B b; C c; } (1) f2()能否访问f1(),i1,j1? 能访问f1()、j1,不能访问i1 (2) b能否访问f1(),i1,j1? 能访问f1(),不能访问i1和j1 (3) f3()能否访问f2()、i2和j2,以及f1(),j1和i1? f3能访问f2()和j2,以及f1()和j1,但不能访问i1和i2 (4)c能否访问f2(),i2和j2?以及f1(),j1和i1? 能访问f2()和f1(),其它的都不能访问
38
该函数返回值为圆半径,为派生类能使用半径提供一个接口
[例6.11]派生类示例程序 #include "iostream.h" class Circle {private: double x,y,r; public: void print() {cout<<"圆心:("<<x<<","<<y<<")"; cout<<endl<<"半径:"<<r<<endl; } void set(double x1,double y1,double r1) { x=x1; y=y1; r=r1; } double getr() {return r;} }; class Cylinder1:public Circle {private: double h; public: void print() {Circle::print(); cout<<"圆柱高:"<<h<<endl; } void set(double x1,double y1, double r1,double h1) { Circle::set(x1,y1,r1); h=h1;} double volume() {double R=getr(); return(3.14*R*R*h); }; void main() {Cylinder1 p; p.set(0,0,2,3); p.print(); cout<<"volume="<<p.volume(); 派生类可访问基类公有成员 该函数返回值为圆半径,为派生类能使用半径提供一个接口
39
派生类名(派生类构造函数总参数表):基类构造函数(参数表1) {<派生类中数据成员初始化>};
3.构造函数和析构函数 派生类的构造函数除了对自己的数据成员初始化外,还负责调用基类构造函数使基类的数据成员得以初始化,当对象被删除时,派生类的析构函数被执行,同时基类的析构函数也将被调用。 格式: 派生类名(派生类构造函数总参数表):基类构造函数(参数表1) {<派生类中数据成员初始化>}; 说明: 基类中有缺省的构造函数或没定义构造函数,则派生类构造函数的定义中可省略对基类构造函数的调用,而隐式调用缺省构造函数。 基类构造函数中,只有有参的构造函数,则派生类构造函数中必须 调用基类构造函数,提供将参数传递给基类构造函数的途径 派生类构造函数的调用顺序为先基类,后派生类。 派生类析构函数的执行顺序为先派生类,后基类。
40
[例6.12]派生类构造函数示例程序 派生类构造函数中调用基类构造函数 class Staff1:public Staff
{private: int wt; public: Staff1(char *n,char s,float w,int t):Staff(n,s,w) {wt=t;} double addwage() {return(wt/10*80);} void display() { Staff::display(); cout<<wt<<", " <<addwage()<<endl; } }; void main() {Staff1s("WangQiang",'m',1526,21); s.display(); #include"iostream.h" #include "string.h" class Staff {private: char name[30]; char sex; float wage; public: void display() {cout<<name<<":"<<sex<<", " <<age<<endl; } Staff(char *n,char s,float w) { strcpy(name,n); sex=s; wage=w; }; 派生类构造函数中调用基类构造函数
41
6.5多态性 6.5.1 运算符重载 发出同样的消息被不同类型的对象接收时导致完全不同的行为。
函数重载(已介绍过) 运算符重载 基于虚函数的多态性 6.5.1 运算符重载 赋予已有的运算符多重含义,通过重新定义运算符使它能够用于特定类的对象以完成特定的功能。 [例6.13]重载“+”运算 ,用以实现两个字符串的连接
42
对加法运算符进行重载 #include "iostream.h" void main() #include "string.h" {
#include "stdio.h" class Str {private: char *s; int len; public: Str() { } Str(char *s1) { len=strlen(s1); s=new char[len]; strcpy(s,s1); } void print() {cout<<s<<endl; } Str operator+(Str s1) { return(strcat(s,s1.s)); } }; void main() { char str1[100],str2[100]; gets(str1); gets(str2); Str s1(str1),s2(str2),s3; s3=s1+s2; s3.print(); } s3=s1.operator+(s2) 对加法运算符进行重载
43
重载形式: 重载为类的成员函数: 类名 operator 运算符(参数表) 程序中表达形式: c1 运算符 c2 编译程序解释形式:
c1 operator 运算符(c2) 重载为类的友元函数: friend类名operator运算符(参数表) 程序中表达形式: c1 运算符 c2 编译程序解释形式: operator 运算符(c1,c2) 隐含了指向c1的this指针 将例6.13中的加法运算符重载为友元函数的形式如下: friend Str operator+(Str s1,Str s2) {return(strcat(s1.s,s2.s));}
44
this 指针 无需定义而隐含于每个类的成员函数中 指向正在被某个成员函数操作的对象 可以用*this来标识调用该成员函数的对象
45
自增重载运算作用于A类对象a #include "iostream.h" class A {private: int x; public:
A(int x1) {x=x1; } void print() {cout<<x<<endl;} A operator++() {x++; return(*this); } }; void main() {A a(5); (++a).print(); 返回调用成员函数的对象自身 等价于如下两条语句: ++a; a.print(); 自增重载运算作用于A类对象a
46
virtual 类型说明符 函数名 (参数表)
6.5.3虚函数 虚函数说明方式 虚函数是动态联编的基础,它是一种非static的成员函数 实现动态联编的条件 virtual 类型说明符 函数名 (参数表) 基类中有说明的虚函数 调用虚函数操作的只能是对象指针或对象引用,否则仍为静态联编 [例6.15]虚函数示例程序
47
观察运行结果 #include "iostream.h" class Animal {public: void character()
{cout<<"动物特征:不同.\n";} virtual food() {cout<<"动物食物:不同.\n";} }; class Giraffe:public Animal {cout<<"长颈鹿特征:长颈.\n";} virtual food() {cout<<"长颈鹿食物:树叶.\n";} class Elephant:public Animal {public: void character() {cout<<"大象特征:长鼻子.\n";} virtual food() {cout<<"大象食物:草.\n";} }; void f(Animal *p)//形参数基类指针 {p->character(); p->food(); } void main() {Giraffe g; f(&g); //实参为派生类对象的地址 Elephant e; f(&e); //实参为派生类对象的地址 观察运行结果
48
若将程序的相应部分修改为如下两种形式,再观察运行结果
void f(Animal &p)//形参为基类 对象的引用 {p.character(); p.food(); } void main() {Giraffe g; f(g);//实参为派生类对象 Elephant e; f(e); //实参为派生类对象 void f(Animal p)//形参为基类 对象 {p.character(); p.food(); } void main() {Giraffe g; f(g);//实参为派生类对象 Elephant e; f(e); //实参为派生类对象
49
虚函数使用说明: 从上述程序中可见: 只有当虚函数操作的是指向对象的指针或是对象的引用时,对该虚函数调用采取的才是动态联编。
派生类中的虚函数应与基类中的虚函数具有相同的名称、参数个数及参数类型。 可以只将基类中的成员函数显式地说明为虚函数,而派生类中的同名函数也隐含为虚函数。
50
6.5.4 抽象类 1.纯虚函数 是一种没有函数体特殊的虚函数,当在基类中不能对虚函数给出有意义的实现,而将其说明为纯虚函数,它的实现留给派生类去做。 格式: virtual 类型 函数名 (参数表)=0; 2. 抽象类 是带有纯虚函数的特殊类,主要作用是将有关的子类组织在一个继承层次结构中,由它来为它们提供一个公共的根。
51
只能用作其它类的基类,不能建立抽象类对象
可说明抽象类指针和引用,指向其派生类,进而实现多态性。 不能用作参数类型、函数返回类型或强制转换的类型。 [例6.16]抽象类示例程序
52
#include <iostream.h> #include <math.h> class base
{protected: int x,y; public: virtual void setx(int i,int j=0) {x=i; y=j;} virtual void disp()=0; }; class square: public base {public: void disp() { cout<<x*x<<endl; } class cube: public base {public: void disp() { cout<<x*x*x<<endl; } }; class chpow: public base cout<<pow(x,y); void main() { base *ptr; square B; cube C; chpow D; ptr=&B; ptr->setx(5); ptr->disp(); ptr=&C; ptr->setx(6); ptr=&D; ptr->setx(3,4); } 抽象类指针 派生类 抽象类指针指向不同的派生类对象B、C、D,实现多态性
53
6.6 程序举例 [例6.17]定义一个汽车类vehicle,其数据成员有车轮个数wheels和车重weight;再定义一个派生类卡车类truck,包含新的数据成员载重量payload及成员函数载重效率。其中: 载重效率=载重量/(载重量+车重) 类名 数据成员 成员函数 vehicle 名称 含义 功能 wheels 车轮个数 初始化数据成员 weight 车重 getwheels、getweight 分别获得各数据成员值 print 输出各数据成员值 truck 基类vehicle类成员 初始化数据成员的值(通过调用基类的构造函数初始化基类成员) payload 载重量 efficiency 求卡车的载重效率 输出数据成员的值(通过调用基类的print函数输出基类成员的值)
54
定义基类 #include "iostream.h" class vehicle {private: int wheels;
float weight; public: vehicle(int wl,float wt) {wheels=wl; weight=wt;} int getwheels() {return wheels; } float getweight() {return weight;} void print() {cout<<"车轮:"<<wheels<<"个"<<endl; cout<<"车重:"<<weight<<"公斤"<<endl; } }; 定义基类
55
派生类构造函数调用基类构造函数 不能直接代之以weight 调用基类成员函数得到车重 class truck:public vehicle
{private: float payload; public: truck(int wl,float wt,float pl):vehicle(wl,wt) {payload=pl;} float efficiency() {return(payload/(payload+vehicle::getweight()));} void print() {cout<<"卡车:"<<endl; vehicle::print(); cout<<"载重:"<<payload<<"公斤"<<endl; cout<<"载重效率:"<<efficiency()<<endl; } }; void main() {truck T(8,4000,300000); T.print();} 派生类构造函数调用基类构造函数 不能直接代之以weight 调用基类成员函数得到车重
56
[例6.18]定义一个下标运算符重载函数,实现数组下标的越界检测
#include <iostream.h> class chararray {private: int length; char *buff; public: chararray(int l) {length=l; buff=new char[length]; } int getlength( ) {return length;} char &operator[](int i) {static char ch=0; if(i<length&&i>=0) return buff[i]; else {cout<<" out of range.";} return ch; } }; void main() {int cnt; chararray string1(6); char *string2="string"; for(cnt=0;cnt<8;cnt++) string1[cnt]=string2[cnt]; cout<<string1[cnt]<<endl; cout<<string1.getlength()<<endl; } 返回值为整型变量的引用 对未超界的元素返回该元素变量 对超界的下标提示超界信息
Similar presentations