本章主要知识点
(1) C++面向对象的程序实例
(2) 类与对象
(3) 继承与派生
(4) 运算符重载本章导读
C语言是一种结构化程序设计语言,它是面向过程的,
在处理较小规模的程序时一般比较容易实现,而当程序规模较大时,C语言就显示出了它的不足。在这种情况下 C++应运而生,C++语言是从 C语言演变而来的,
它保留了 C语言的所有优点,同时也增加了面向对象的功能。现在 C++已成为程序设计中应用最广泛的一种语言。
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本书目录第 10章 C++面向对象程序设计第 10章 C++面向对象程序设计
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章导读
10.2 类与对象
10.3 继承与派生
10.5 综合实训
10.4 运算符重载
10.1 C++面向对象的程序实例
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
10.1.2 C++语言概述
10.1.1 C++面向对象的程序实例
10.1 C++面向对象的程序实例
10.1.1 C++面向对象的程序实例
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
2,C++程序实例 (2)
3,C++程序实例 (3)
1,C++程序实例 (1)
【 例 10.1】 定义一个矩形类。( 程序名为 l10_1.cpp。)
#include<iostream.h>
class rectangle //定义一个矩形类
{ public:
rectangle(float len,float wid) //构造函数
{ length=len;
width=wid;
}
float GetArea(); //声明成员函数,计算矩形面积
float GetPerimeter(); //声明成员函数,计算矩形周长
~rectangle(){} //析构函数
private:
float length; //私有数据
float width;
};
10.1.1 C++面向对象的程序实例
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
1.C++程序实例 1
float rectangle::GetArea() //成员函数的具体实现
{ return length*width;
}
float rectangle::GetPerimeter() //成员函数的具体实现
{ return 2*(length+width);
}
void main()
{ float l,w;
cout<<"请输入矩形的长和宽,";
cin>>l>>w;
rectangle x(l,w); //定义一个矩形类对象
cout<<x.GetArea()<<endl;
cout<<x.GetPerimeter()<<endl; //调用成员函数
}
10.1.1 C++面向对象的程序实例
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
10.1.1 C++面向对象的程序实例
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录实例 1的功能是定义一个矩形类,该类有长和宽两个数据成员,用来描述矩形的静态特征(属性),有构造函数用来用初始化类对象,另外还有计算面积和周长两个成员函数作为该类的外部接口,供类外的程序访问。当用户输入矩形的长和宽之后,将构造一个实例矩形,并输出矩形的面积和周长。
例如用户输入 5,6< CR >,则输出结果为,
30
22
【 例 10.2】 类的派生。(程序名为 l10_2.cpp。)
#include<iostream.h>
class rectangle //定义矩形类
{ public:
void InitRect(float len,float wid) //定义类的成员函数
{ length=len;
width=wid;
}
float GetArea();
float GetPerimeter();
private,//定义私有成员变量
float length;
float width;
};
float rectangle::GetArea() //成员函数实现
{ return length*width;}
10.1.1 C++面向对象的程序实例
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
2.C++程序实例 2
float rectangle::GetPerimeter() //成员函数实现
{ return 2*(length+width);
}
class square:public rectangle //从矩形类中派生新类 (正方形类 )
{public:
void InitSquare(float b){InitRect(b,b);} //新增的成员函数 (初始化
}; //正方形 )
void main()
{ square x; //声明正方形类对象
x.InitSquare(8); //调用正方形类新增的成员函数
cout<<x.GetArea()<<endl; //调用从矩形类中继承下来的成员函数
cout<<x.GetPerimeter()<<endl; //调用从矩形类中继承下来的成员
} //函数 (GetPerimeter)
10.1.1 C++面向对象的程序实例
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
10.1.1 C++面向对象的程序实例
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录实例 2的功能是先定义一个矩形类,然后从该矩形类中派生出一个新的正方形类(正方形是矩形的一个特例)。
程序中先声明一个正方形类对象,然后将其初始化为边长为 8的正方形,再调用从矩形类中继承下来的计算面积和周长两个函数,计算出正方形的面积和周长。该程序的输出结果为:
64
32
【 例 10.3】,+”运算符重载。(程序名为 l10_3.cpp。)
#include<iostream.h>
class rectangle //定义一个矩形类
{public:
rectangle(float len=0,float wid=0) //构造函数
{ length=len;
width=wid;
}
float GetArea(){return length*width;} //成员函数 (计算面积 )
rectangle operator +(rectangle a2) //将 "+"运算符重载
{ rectangle a; //用于两个矩形对象相加
a.length=length;
a.width=width+a2.GetArea()/length;
return rectangle(a.length,a.width);
}
10.1.1 C++面向对象的程序实例
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
3.C++程序实例 3
private,//私有成员变量
float length;
float width;
};
void main()
{ rectangle x(5,9),y(5,6),z; //声明类对象
cout<<"第一个矩形面积为,"<<x.GetArea()<<endl;
cout<<"第二个矩形面积为,"<<y.GetArea()<<endl;
z=x+y; //对两个矩形相加
cout<<"两个矩形面积之和为,"<<z.GetArea()<<endl;
}
10.1.1 C++面向对象的程序实例
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录实例 3的功能是先定义一个矩形类,然后将,+”运算符重载为可以使两个矩形类对象相加。该程序的输出结果为:
第一个矩形面积为,45
第二个矩形面积为,30
两个矩形面积之和为,75
10.1.2 C++语言概述
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录由于结构化程序设计自身的不足,在 20世纪 80年代出现了面向对象程序设计方法,C++语言也由此而产生。
面向对象程序设计( Object-Oriented programming,简称 OOP)设计的出发点就是为了能更直接的描述客观世界中存在的事物(即对象)以及它们之间的关系。面向对象程序设计是对结构化程序设计的继承和发展,它认为现实世界是由一系列彼此相关且能相互通信的实体组成,这些实体就是面向对象方法中的对象,而对一些对象的共性的抽象描述,就是面向对象方法中的类。类是面向对象程序设计的核心。
10.1.2 C++语言概述
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
C++是目前最流行的面向对象程序设计语言。它在 C语言的基础上进行了改进和扩充,并增加了面向对象程序设计的功能,更适合于开发大型的软件。 C++是由贝尔实验室在 C语言的基础开发成功的,C++保留了 C语言原有的所有优点,同时与 C语言又完全兼容。它既可以用于结构化程序设计,又可用于面向对象程序设计,因此 C++是一个功能强大的混合型程序设计语言。
C++最有意义的方面是支持面向对象程序设计的特征。
虽然与 C语言的兼容性使得 C++具有双重特点,但它在概念上和 C语言是完全不同的,学习 C++应该按照面向对象程序的思维去编写程序。
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
10.2.2 类的构造与封装
10.2.1 面向对象的基本概念
10.2 类与对象
10.2.3 创建对象
10.2.4 友元
10.2.5 模板
10.2.6 程序实训
10.2.1 面向对象的基本概念
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
1,对象从一般意义上讲,客观世界中任何一个事物都可以看成是一个对象。例如一本书,一名学生等。对象具有自己的静态特征和动态特征。静态特征可以用某种数据来描述,如一名学生的身高、年龄、性别等;动态特征是对象所表现的行为或具有的功能,如学生学习、运动、
休息等。
面向对象方法中的对象是系统中用来描述客观事物的一个实体,它是用来构成系统的一个基本单位,对象由一组属性和一组行为构成。属性是用来描述对象静态特征的数据项,行为是用来描述对象动态特征的操作序列。
许多对象具有相同的结构和特性,例如不管是数学书还是化学书,它们都具有大小、定价、编者等特性。在现实生活中,我们通常将具有相同性质的事物归纳、划分成一类,例如数学书和化学书都属于书这一类。同样在面向对象程序设计中也会采用这种方法。面向对象方法中的类是具有相同属性和行为的一组对象的集合。
类代表了一组对象的共性和特征,类是对象的抽象,
而对象是类的具体实例。例如,家具设计师按照家具的设计图做成一把椅子,那么设计图就好比是一个类,而做出来的椅子则是该类的一个对象,一个具体实例。拿 【 例
10.1】 中定义的矩形类来说,该类只是所有矩形的一个蓝本,它只是代表了矩形的一些特征,而该类的实例则是一个特定的矩形。
10.2.1 面向对象的基本概念
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
2.类
10.2.2 类的构造与封装
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
1.类的封装类的封装就是将对象的属性和行为结合成一个独立的实体,
并尽可能隐蔽对象的内部细节,对外形成一道屏障,只保留有限的对外接口使之和外界发生联系。类的成员包括数据成员和成员函数,分别描述类所表达问题的属性和行为。
对类成员的访问加以控制就形成了类的封装,这种控制是通过设置成员的访问权限来实现的。
在面向对象程序设计中,通过封装将一部分行为作为外部接口,而将数据和其它行为进行有效的隐蔽,就可以达到对数据访问权限的合理控制。把整个程序中不同部分的相互影响减少到最低限度。
10.2.2 类的构造与封装
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
2.类的定义类定义的一般格式为:
class 类名称
{
public:
公有数据和成员函数 /*外部接口 */
protected:
保护数据的成员函数
private:
私有数据和成员函数
};
10.2.2 类的构造与封装
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录关键字 class说明了类定义的开始,类中所有的内容用大括号括起来。类的成员可分为三种级别的访问权限:
public(公有的):说明该成员是公有的,它不但可以被类的成员函数访问,而且可以被外界访问,所以说公有类型定义了类的外部接口。
Protected(保护的):说明该成员只能被该类的成员函数和该类的派生类的成员函数访问。
Private(私有的):说明该成员只能被类的成员函数访问,
外界不能直接访问它。类的数据成员一般都应该声明为私有成员。
10.2.2 类的构造与封装
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
3.类的成员函数类的成员函数描述的是类的行为。定义类时在类定义体中给出函数的声明,说明函数的参数列表和返回值类型,而函数的具体实现一般在类定义体之外给出。下面是类外定义成员函数的一般格式:
返回值类型 类名,:类成员函数名 (参数列表 )
{
函数体
}
其中,:称为作用域分辨符。用它可以限制要访问的成员所在的类的名称。
在建立一个对象时,常常需要作一些初始化工作,而当对象使用结束时,又需要作一些清理工作。在 C++中提供了两个特殊的成员函数来完成这两项工作,那就是构造函数和析构函数。
构造函数的作用就是在对象在被创建时利用特定的值构造对象,将对象初始化。构造函数完成的是一个从一般到具体的过程。需要注意的是构造函数同其它的成员函数不同,
它不需要用户触发,而是在创建对象时由系统自动调用,
其它任何过程都无法再调用构造函数。构造函数的函数名必须与类名相同,而且不能有返回值,也不需加 void类型声明。构造函数可以带参数也可以不带参数。构造函数一般定义为公有类型。
10.2.2 类的构造与封装
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
4.构造函数和析构函数
10.2.2 类的构造与封装
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录析构函数也是类的一个公有成员函数,其作用与构造函数正好相反,它是用来在对象被删除前进行一些清理工作。
析构函数调用之后,对象被撤消了,相应的内存空间也将被释放。析构函数名也应与类名相同,只是函数名前加一个波浪符,~”,以区别于构造函数。析构函数不能有任何参数,且不能有返回值。如果不进行显式说明,系统会自动生成缺省的析构函数,所以一些简单的类定义中没有显式的析构函数。
5.构造函数与析构函数应用实例
10.2.2 类的构造与封装
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
【 例 10.4】 程序名为 l10_4.cpp。
#include<iostream.h>
class A //定义类 A
{ public:
A()
{ cout<<“构造函数被调用” <<endl; //构造函数
}
void disp() //成员函数
{ cout<<“构造函数与析构函数应用举例” <<endl;
}
~A() //析构函数
{ cout<<"析构函数被调用 "<<endl;
}
};
程序在声明 A类的对象时,系统会自动调用构造函数,因而先执行构造函数中的输出语句,输出“构造函数被调用”,接下来调用 disp成员函数,执行 disp成员函数中的输出语句,输出“构造函数与析构函数应用举例”,最后程序在退出前由系统自动调用析构函数,执行析构函数中的输出语句,输出“析构函数被调用”,因此程序的输出结果为:
构造函数被调用构造函数与析构函数应用举例析构函数被调用
10.2.2 类的构造与封装
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
void main()
{ A a; //声明类对象,自动调用构造函数
a.disp(); //调用成员函数,对象使用结束时
//自动调用析构函数
}
6.实例分析
10.2.3 创建对象
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录通过使用数组,我们可以对大量的数据和对象进行有效的管理,但对于许多程序,在运行之前,我们并不能确切地知道数组中会有多少个元素。例如,一个网络中有多少个可用节点,一个 CAD系统中会用到多少个形状等。如果数组开的太大会造成很大的浪费,如果数组较小则又影响大量数据的处理。在 C++中,动态内存分配技术可以保证我们在程序运行过程中按实际需要申请适量的内存,使用结束后再进行释放。这种在程序运行过程中申请和释放存储单元的过程称为创建对象和删除对象。
1,new运算符
C++用 new运算符来创建对象。
运算符 new的功能是动态创建对象,其语法形式为:
new 类型名 (初值列表 );
该语句的功能是在程序运行过程中申请用于存放指定类型的内存空间,并用初值列表中给出的值进行初始化。
如果创建的对象是普通变量,初始化工作就是赋值,如果创建的对象是某一个类的实例对象,则要根据实际情况调用该类的构造函数。
例如,int *p;
p=new int(100); //赋值给指针变量例如,rectangle *r;
r=new rectangle(5,6); //调用矩形类的构造函数如果创建的对象是数组类型,则应按照数组的结构来创建,
其语法形式为:
10.2.3 创建对象
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
10.2.3 创建对象
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录一维数组,new 类型名 [下标 ];
当数组为一维数组时,下标为数组为元素的个数,动态分配内存时不能指定数组元素的初值。如果内存申请成功,
返回一个指向新分配内存的首地址的指定类型的指针,如果失败返回 0。
例如,int *p;
p=new int[10];
多维数组,new 类型名 [下标 1][下标 2]…… ;
当数组为多维数组时,返回一个指向新分配内存的首地址的指针,但该指针的类型为指定类型的数组。数组元素的个数为除最左边一维外下标的乘积。
例如,int (*p)[5];
p=new int[10][5];
10.2.3 创建对象
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
2,delete运算符运算符 delete的功能是删除由 new运算符创建的对象,释放指针指向的内存空间,其语法形式为:
delete 指针名;
例如,int *p;
p=new int(100);
delete p;
如果 new 运算符创建的对象是数组,则删除对象时应使用的语法形式为:
delete []指针名;
例如,int *p;
p=new int[10];
delete []p;
10.2.3 创建对象
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
3,C++程序实例
【 例 10.5】 类对象的创建与删除。(程序名为 l10_5.cpp。)
#include<iostream.h>
class rectangle //定义一个矩形类
{public:
rectangle(float len,float wid) //构造函数
{ length=len;
width=wid;
}
float GetArea(); //成员函数
private:
float length;
float width;
};
10.2.3 创建对象
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
float rectangle::GetArea() //成员函数实现
{ return length*width;
}
void main()
{ rectangle *r; //定义指向 rectangle类的指针变量 r
r=new rectangle(10,5); //创建 rectangle类对象
cout<<r->GetArea()<<endl;
delete r; //删除对象
}
4,C++程序实例分析程序中先建立了一个 rectangle类,然后在主函数中定义了一个指向
rectangle类的指针变量 r,用 new在内存中开辟一段空间以存放
rectangle类对象,这时会自动调用构造函数来初始化该对象,接下来使用指向 rectangle类的指针变量 r得到矩形的面积,最后用 delete删除对象,释放该空间。
10.2.4 友元
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
2,友元函数
3,友元类
1,友元概述
10.2.4 友元
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录在程序设计过程中,假如用户建立了一个类,这个类的数据成员被定义为私有,这时如果想把该数据存取到某个函数(非该类的成员函数)中,那么这样作肯定是不被允许的。但是有时候一些非成员函数需要亲自访问类中的某些私有数据,那么这时候就需要用到友元。友元提供了不同类或对象的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。通过友元,一个普通函数或类的成员函数可以访问到封装于其它类中的数据。友元的作用在于提高程序的运行效率,但同时它也破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。
1.友元概述
10.2.4 友元
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录友元函数是在类定义中由关键字 friend修饰的非成员函数。友元函数可以是一个普通函数,也可以其它类中的一个成员函数,它不是本类的成员函数,但它可以访问本类的私有成员和保护成员。友元函数需要在类的内部进行声明。其格式如下:
class 类名称
{
类的成员声明
friend 返回类型 友元函数名 (参数列表 );
类的成员声明
}
2.友元函数
10.2.4 友元
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
【 例 10.6】 使用友元函数计算两点间的距离。
程序名为 l10_6.cpp。
#include <iostream.h>
#include <math.h>
class Point //定义 Point类 (点 )
{public:
Point(double xx,double yy) //构造函数
{x=xx;
y=yy;}
void Getxy(); //成员函数声明
friend double Distance(Point &a,Point &b);//友元函数声明
private:
double x,y; //私有成员 (点的坐标 )
};
void Point::Getxy() //成员函数实现
{cout<<“(”<<x<<“,”<<y<<“)”; //输出点的坐标
}
double Distance(Point &a,Point &b) //友元函数实现
{ double dx = a.x - b.x; //访问私有成员
double dy = a.y - b.y;
return sqrt(dx*dx+dy*dy); //两点距离
}
void main()
{ Point p1(3.0,4.0),p2(6.0,8.0); //定义 Point类对象
p1.Getxy(); //调用成员函数
p2.Getxy();
cout<<“\nThe istance is,<<Distance(p1,p2)<<endl;
//调用友元函数
}
10.2.4 友元
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
10.2.4 友元
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录实例说明,程序在类定义体内声明了友元函数的原形,
在声明时函数名前加 friend关键字进行修饰,友元函数的具体实现在类外给出,可以看出友元函数通过对象名可直接访问 Point类的私有成员,而不需要借用外部接口 Getxy。在调用友元函数时同调用普通函数一样,
采用直接调用方法,而不需要像调用类的成员函数那样必须通过对象。
该程序的输出结果为:
(3,4)(6,8)
The distance is 5
10.2.4 友元
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
3.友元类同函数一样,类也可以声明为另一个类的友元,这时称为友元类。当一个类作为另一个类的友元时,这个类的所有成员函数都将是另一个类的友元函数。
友元类的一般格式为:
class 类 A
{
类 A的成员声明
friend class 类 B;
类 A的成员声明
}
【 例 10.7】 程序名为 l10_7.cpp。
#include<iostream.h>
class A //定义类 A
{ public:
A(int xx,int yy) //类 A的构造函数
{ x=xx;
y=yy;
}
friend class B; //声明类 B为类 A的友元类
private:
int x,y;
};
class B //定义类 B
{public:
void disp1(A s)
{cout<<"disp1调用了类 A的私有成员 x:"<<s.x<<endl;}
//类 B的成员函数访问类 A的私有成员
10.2.4 友元
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录程序中定义了 A和 B两个类,其中类 B为类 A的友元类,定义时在类 A的内部声明类 B,而类 B的具体实现过程是在类 A的外部。类 B
中有两个成员函数 disp1和 disp2,根据友元类的概念,这两个成员函数都成为类 A的友元函数,所以它们都可以访问类 A的私有成员
x和 y。该程序的输出结果为:
disp1调用了类 A的私有成员 x:5
disp2调用了类 A的私有成员 y:9
10.2.4 友元
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
void disp2(A s)
{ cout<<"disp2调用了类 A的私有成员 y:"<<s.y<<endl;}
//类 B的成员函数访问类 A的私有成员
};
void main()
{
A a(5,9); //声明 A类对象
B b; //声明 B类对象
b.disp1(a); //调用 B类的成员函数
b.disp2(a);
}
10.2.5 模板
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录前面章节中我们学习了重载函数,使用重载函数可以处理多种数据类型,但是即使设计为重载函数也只是使用相同的函数名,函数体仍然要分别定义。
使用函数模板则不同了,函数模板可以用来创建一个通用功能的函数,以支持多种不同的参数,简化重载函数的函数体设计。函数模板的定义形式为:
template <typename 标识符 >
函数定义
1.函数模板
10.2.5 模板
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
【 例 10.8】 使用函数模板。(程序名为 l10_8.cpp。)
#include <iostream.h>
template <typename T>
T max(T x,T y) //定义模板函数
{ return x>y?x:y;
}
void main()
{ int a=6,b=8;
cout<<max(a,b)<<endl;
double m=10.5,n=8.5;
cout<<max(m,n)<<endl;
}
程序中首先定义模板函数 max用来取得两个数中相对较大的一个,然后主函数调用该函数,此时编译器将根据实参的类型推导出函数模板的类型参数。例如,当调用 max(a,b)时,由于 a,b为整型变量,所以模板中类型参数 T为 int,而调用 max(m,n)时,由于 m,n为 double类型,所以模板中类型参数 T为 double。
10.2.5 模板
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
2.类模板使用类模板使用户可以为类定义一种模式,使得类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值能取任意类型,包括用户自定义的或系统预定义的。
为了定义类模板,应在类的声明之前加上一个模板参数表,
参数表里的形式类型名用来说明成员数据和成员函数的类型。类模板的定义形式为:
template <class 类型说明符 >
类定义类模板自身不产生代码,它指定类的一个家族,当被其它代码引用时,类模板才根据引用的需要产生代码。
【 例 10.9】 使用类模板。(程序名为 l10_9.cpp。)
#include<iostream.h>
template <class T> //类模板,实现对任意数据类型的存取 class
rectangle //定义一个矩形类 rectangle
{public:
rectangle(T len,T wid) //构造函数
{ length=len;
width=wid;
}
T GetArea(); //声明成员函数,计算矩形面积
T GetPerimeter(); //声明成员函数,计算矩形周长 private:
T length; //私有数据,用于任意类型
T width;
};
template <class T>
T rectangle<T>::GetArea() //成员函数的具体实现
{ return length*width;}
10.2.5 模板
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
template <class T>
T rectangle<T>::GetPerimeter() //成员函数的具体实现
{ return 2*(length+width);}
void main()
{ rectangle<int> x(4,6); //定义 rectangle对象 (成员函数返回值为 int型 )
rectangle<double> y(5.5,3.8); //定义 rectangle对象 (成员函数返回值为
double型 )
cout<<“x的面积是,”<<x.GetArea()<<endl;
cout<<“x的周长是,”<<x.GetPerimeter()<<endl;
cout<<“y的面积是,"<<y.GetArea()<<endl;
cout<<"y的周长是,"<<y.GetPerimeter()<<endl;
}
程序的执行结果为:
x的面积是,24
x的周长是,20
y的面积是,20.9
y的周长是,18.6
10.2.5 模板
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
【 例 10.10】 日期类应用程序举例。(程序名为 l10_10.cpp。)
#include<iostream.h>
class TDate //日期类的定义
{public:
TDate(int y,int m,int d); //构造函数
int IsLeapYear(); //判断闰年
void show(); //显示日期
friend int Getyear(TDate date); //友元函数,返回年
private:
int year,month,day;
};
TDate::TDate(int y,int m,int d) //构造函数实现
{ year=y;
month=m;
day=d;
}
10.2.6 程序实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
1,C++程序实例
int TDate::IsLeapYear()
{ return(year%4==0 && year%100!=0) || (year%400==0);}
void TDate::show()
{ cout<<year<<“年” <<month<<“月” <<day<<“日” <<endl;}
int Getyear(TDate date) //友元函数实现
{ return date.year;}
void main()
{ TDate *date; //声明指向 TDate类型的指针变量
date=new TDate(2008,10,28); //创建对象
date->show(); //调用成员函数
if(date->IsLeapYear())
cout<<Getyear(*date)<<“年是闰年” <<endl; //调用友元函数
else
cout<<Getyear(*date)<<“年不是闰年 "<<endl;
delete date; //删除对象
}
10.2.6 程序实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
10.2.6 程序实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录程序可以分为三个部分,第一部分是 CDate类的定义,第二部分是成员函数的实现,第三部分是主函数。类定义中仍然是由成员数据和成员函数组成,其中成员函数作为外部接口。
程序中为了说明友元的应用,引入了友元函数,这里可以换成类的成员函数,读者可以自己试一试。主函数中,在定义了指向 TDate类型的指针变量之后,使用 new运算符创建对象,
程序结束时又使用 delete运算符删除了对象,释放了内存空间。这种编程方法在以后的程序设计中会经常遇到,读者应该习惯于使用 new和 delete 进行动态内存管理。
2,C++程序实例分析
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
10.3.2 派生类
10.3.1 继承与派生的概念
10.3 继承与派生
10.3.4 虚函数
10.3.3 派生类的构造函数与析构函数
10.3.5 程序实训面向对象程序设计过程中,一个很重要的特点就是代码的可重用性。 C++是通过继承这一机制来实现代码重用的。所谓继承指的是类的继承,就是在原有类的基础上建立一个新类,新类将从原有类那里得到已有的特性。例如,现有一个学生类,定义了学号、姓名、性别、年龄四项内容,如果我们除了用到以上四项内容外,还需要用到电话和地址等信息,我们就可以在学生类的基础上再增加相关的内容,而不必重头再定义一个类。
换个角度来说,从已有类产生新类的过程就是类的派生。类的继承与派生允许在原有类的基础上进行更具体、更详细的修改和扩充。新的类由原有的类产生,包含了原有类的关键特征,同时也加入了自己所特有的性质。新类继承了原有类,原有类派生出新类。原有的类我们称为基类或父类,而派生出的类我们称为派生类或子类。比如:所有的 windows应用程序都有一个窗口,
可以说它们都是从一个窗口类中派生出来的,只不过有的应用程序用于文字处理,有的则应用于图像显示。
10.3.1 继承与派生的概念
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
10.3.1 继承与派生的概念
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录类的继承与派生的层次结构是人们对自然界中事物进行分类分析认识过程在程序设计中的体现。现实世界中的事物都是相互联系、相互作用的,人们在认识过程中,根据它们的实际特征,抓住其共同特性和细小差别,利用分类的方法进行分析和描述。
如下图是生物类的一种继承图,最高层次的生物类是抽象程度最高的,是最具有普遍意义的概念,下层具有上层的特性,同时也加入了自己新的特性,而最下层是最具体的。
这个层次结构中,由上到下,是一个具体化、特殊化的过程,
由下到上,是一个抽象化的过程。上下层之间就可以看作是基类与派生类的关系。
10.3.1 继承与派生的概念
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
10.3.2 派生类
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录定义派生类的一般形式为:
class 派生类名,继承方式 基类名
{ 派生类成员定义 };
继承方式指派生类的访问控制方式,可以是 public(公有继承),protected(保护继承)和 private(私有继承)。
继承方式可以省略不写,缺省值为 private。
派生类在派生过程中,需要经历 吸收基类成员,改造基类成员 和 添加新成员 三个步骤。其中,吸收基类成员主要目的是实现代码重用,但应该注意的是基类的构造函数和析构函数是不能被继承下来的;改造基类成员则主要是对基类数据成员或成员函数的覆盖,就是在派生时定义一个和基类数据或函数同名的成员,这样基类中的成员就被替换为派生类中的同名成员;添加新成员是对类功能的扩展,添加必要的数据成员和成员函数来实现新增功能。
10.3.2 派生类
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录在继承中,派生类继承了除构造函数和析构函数以外的全部成员。对于从基类继承过来的成员的访问并不是简单的把基类的私有成员、保护成员和公有成员直接作为私有成员、保护成员和公有成员,而是要根据基类成员的访问权限和派生类的继承方式共同决定。
1.公有继承当类的继承方式为 public时,基类的公有( public)成员和保护( protected)成员仍然成为派生类的公有成员和保护成员,而基类的私有成员不能被派生类访问。
2.保护继承当类的继承方式为 protected时,基类的公有( public)成员和保护( protected)成员将成为派生类的保护成员,而基类的私有成员不能被派生类访问。
10.3.2 派生类
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

3.私有继承当类的继承方式为 private时,基类的公有( public)成员和保护( protected)成员将成为派生类的私有成员,而基类的私有成员不能被派生类访问。 (看下图,)
返回本节目录如 10.1.1中实例 2先定义了一个矩形类,然后又从矩形类中派生出正方形类,正方形是矩形的一个特例,矩形类实例化一个矩形对象时需要用到长和宽两个参数,而正方形则只需要用到边长一个参数,所以在派生过程中新增了成员函数
InitSquare用来完成初始化工作。 InitSquare函数实现过程中用到了基类的成员函数 InitRect,因为 InitRect函数为基类的公有成员,所以在派生类中可以被访问。如果 InitSquare函数的实现过程改为如下语句:
void InitSquare (float b)
{ length=b;
width=b; }
该程序是不能被编译通过的,因为派生类是不能访问基类的私有成员的。另外,该程序使用的继承方式为公有继承,因此基类中的公有成员都被派生类吸收并成为公有成员。
10.3.2 派生类
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
10.3.3 派生类的构造函数与析构函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录继承的目的是为了发展,派生类继承了基类的成员,
实现了代码重用,这只是一部分,而代码的扩充才是最主要的,只有添加新的成员,加入新的功能,类的派生才有实际意义。我们知道,基类的构造函数和析构函数是不能被继承的,因此如果要对新增成员进行初始化,就必须加入新的构造函数。同样,对派生类对象的扫尾、清理工作也需要引入新的析构函数。
1.派生类的构造函数如果基类的对象包含对成员的初始化,而在建立派生类对象时,由于基类的构造函数不能被继承而无法执行,因此会使基类的成员未初始化,所以在设计派生类的构造函数
10.3.3 派生类的构造函数与析构函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录时,不仅要考虑派生类新增的数据成员的初始化,还应当考虑基类数据成员的初始化。
派生类构造函数的一般格式为:
派生类构造函数名(参数列表):基类构造函数名(参数列表)
{
派生类新增成员初始化语句;
}
将 【 例 10.2】 改为使用构造函数进行初始化:
【 例 10.11】 程序名为 l10_11.cpp。
#include<iostream.h>
class rectangle //定义矩形类 (基类 )
{public:
rectangle(float len,float wid) //基类的构造函数
{ length=len;
width=wid;
}
float GetArea();
float GetPerimeter();
private,//定义私有成员变量
float length;
float width;
};
float rectangle::GetArea() //基类成员函数实现
{ return length*width;
}
float rectangle::GetPerimeter() //基类成员函数实现
{ return 2*(length+width);
}
class rect:public rectangle //从矩形类中派生新类 (正方形类 )
{public:
rect(float b):rectangle(b,b) //派生类的构造函数
{}
};
10.3.3 派生类的构造函数与析构函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
10.3.3 派生类的构造函数与析构函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
void main()
{ rect x(8); //声明正方形类对象
cout<<x.GetArea()<<endl; //调用从矩形类中继承
//下来的成员函数 (GetArea)
cout<<x.GetPerimeter()<<endl; //调用从矩形类中继承下来
//的成员函数 (GetPerimeter)
}
程序的输出结果为:
64
32
10.3.3 派生类的构造函数与析构函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
2.派生类的析构函数在派生过程中,基类的析构函数也不能被继承下来,这就需要在派生类中自行定义 。 派生类析构函数的定义与没有继承关系的类的析构函数完全相同,只要负责把派生类新增的成员的清理工作做好就够了,系统会自动调用基类的析构函数对基类对象成员进行清理 。 同构造函数相同,析构函数在执行过程中也要对基类进行操作,
它首先对派生类新增成员进行清理,然后对基类进行清理 。 这些清理工作分别是调用派生类析构函数和调用基类析构函数来完成的 。
【 例 10.12】 程序名为 l10_12.cpp。
#include <iostream.h>
class color //定义 color类
{public:
void paint(){cout<<“No color.”<<endl;}
};
class green:public color //由 color派生出 green类
{public:
void paint(){cout<<"The color is green."<<endl;}
};
10.3.4 虚函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录虚函数就是在前面使用 virtual 关键字来限定的普通成员函数。
虚函数是为实现某种功能而假设的函数,它是类的一个成员函数。
当在派生类中定义了一个同名的成员函数时,只要该成员函数的参数类型及返回类型与基类中同名的虚函数完全一样,那么无论是否用 virtual关键字,它都将成为一个虚函数。
我们先看一个例子:
10.3.4 虚函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
void main()
{ color c,*p; //声明 color类变量及指针变量
green g; //声明 green类变量
p=&g; //将指向 color类的指针 p指向 green类
c.paint();
g.paint();
p->paint();
}
程序执行结果如右图:
10.3.4 虚函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

程序中对象 c和对象 g的输出结果都不难理解,但指针 p已经指向了 green类的对象,然而从输出结果看调用的却是 color
类的 paint()函数。解决这个问题的方法就是使用虚函数。
将上例 color类改为如下使用虚函数的方法:
class color //定义 color类
{public:
virtual void paint(){cout<<"No color."<<endl;} //定义虚函数
};
输出结果如右图:
返回本节目录
10.3.4 虚函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录以上实例说明在 C++中,如果一个函数被定义成虚函数,
那么,即使是使用指向基类对象的指针来调用该成员函数,
C++也能保证所调用的是正确的特定于实际对象的成员函数。
10.3.5 程序实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录使用类的派生编程实现在屏幕上显示某学生的选课信息。学生包括姓名和学号两个属性,选课信息包括课程名称、任课教师和上课时间三个属性,每名学生最多可选三门课。
由于学生包括两个属性,选课信息包括三个属性,而这些属性都可以用字符数组表示,那么抓住这个共性我们就可以考虑建立一个基类( base),使其具有两个字符数组类型的成员变量,接下来我们就可以由该基类派生出学生类( student)和选课信息类( classes)。为了显示相关信息,在派生的过程中,需要增加相应的外部接口。程序的具体实现代码如下:
10.3.5 程序实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

【 例 10.14】 程序名为 l10_14.cpp。
#include<iostream.h>
#include<string.h>
class base //定义基类 base
{ private:
char str1[20];
char str2[10];
public:
base(){}
base(char s1[],char s2[])
{ strcpy(str1,s1);
strcpy(str2,s2);
}
void show1()
{ cout<<str1;
}
返回本节目录
10.3.5 程序实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
void show2()
{ cout<<str2;
}
};
class classes:public base //从基类派生课程类
{private:
char cname[20]; //课程名称
public:
classes(){}
classes(char cna[],char cweek[],char ctea[]):base(cweek,ctea)
//课程名称、上课时间、任课教师
{strcpy(cname,cna);}
void show()
{ cout<<cname<<“(”;
show1(); //课程名称 (任课教师,上课时间 )
cout<<“,”;
show2();
cout<<“)”;
}
};
class student:public base //从基类派生学生类
{ private:
classes cls[3]; //每名学生最多选修 3门课
int max;
public:
student(){}
student(char sname[],char sno[]):base(sname,sno){max=0;}
10.3.5 程序实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
10.3.5 程序实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
void selectcls(classes c) //选课
{ cls[max]=c;
max++;
}
void showcls() //显示选课信息
{ cout<<“学生:” ;
show1();
cout<<"(";
show2();
cout<<")"<<endl<<"选修课程,"<<endl;
for(int i=0;i<max;i++)
{ cout<<i+1<<":";
cls[i].show();
cout<<endl;
}
}
};
10.3.5 程序实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
void main()
{ student stu("黄雪菲 ","12345678");
classes cls1("数据库应用 ","曲子研 ","星期三 ");
classes cls2("C++程序设计 ","胡小燕 ","星期二 ");
classes cls3("数据结构 ","江山 ","星期五 ");
stu.selectcls(cls1);
stu.selectcls(cls2);
stu.selectcls(cls3);
stu.showcls();
}
程序的执行结果如右图:
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
10.4.2 运算符重载规则
10.4.1 重载运算符
10.4 运算符重载
10.4.3 类型转换与转换函数
10.4.1 重载运算符
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录运算符重载增强了 C++ 语言的可扩充性。在 C++ 中,定义一个类就是定义了一个新类型。因此,类对象和变量一样,
可以作为参数传递,也可以作为返回类型。在基本数据类型中,系统提供了许多预定义的运算符,而实际上,对于用户自定义的类型(比如类),也需要有类似的运算操作,这就提出了对运算符进行重新定义,赋于已有符号以新的功能要求。
运算符重载的实质是函数重载。所谓函数重载简单地说就是赋给同一个函数名多个含义,C++中允许在相同的作用域内以相同的名字定义几个不同的函数,可以是成员函数,也可以是非成员函数,定义重载函数时要求函数的参数或者至少有一个类型不同,或者个数不同,而对于返回值的类型可以相同,也可以不同。对于每一个运算符 @,都对应于一个
10.4.1 重载运算符
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录运算符函数 operator@,例如,+”对应的运算符函数是
operator+。运算符重载在实现过程中首先把指定的运算符转化为对运算符函数的调用,再把运算对象转化为运算符函数的实参,然后根据实参的类型来确定需要调用的运算符函数。
例如在 10.1.1实例 3中,我们把,+”重载为矩形类的成员函数,那么就可直接进行两个矩形类对象相加了。可以看出,
运算符重载除了在函数声明时使用了关键字 operatore之外,其它地方与类的普通成员函数没什么区别,只不过它可以直接通过运算符和操作数的方式来完成函数的调用。
运算符重载扩充了运算符原有的功能,如 10.1.1实例 3中对,+”进行了运算符重载之后,,+”的原有功能不变,对整型、浮点型数据的运算仍然遵循 C++预定义的规则,同时又增加了针对矩形类运算的功能。,+”作用于不同的对象上,就会导致不同的操作行为,具有了更广泛的功能。
10.4.2 运算符重载规则
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录运算符重载的规则如下:
1) C++中的运算符除了少数几个外,全部可以重载,而且只能重载已有的这些运算符。
2) 重载之后运算符的优先级和结合性保持不变。
3) 运算符重载是针对新类型数据的实际需要,对原有运算符进行适当的改造。一般来讲,重载的功能应与原有的功能相类似,不能改变原有运算符的操作对象个数,同时至少有一个操作对象是自定义类型。
不能重载的运算符有五个,它们是是类属关系运算符,.”、
指针运算符,*”、作用域运算符,::”、三目运算符,?:”和
sizeof运算符。
运算符的重载形式有两种,重载为类的成员函数和重载为友元函数。重载为类的成员函数的一般形式为:
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录类名称 operator 运算符 (参数表 )
{
函数体
}
重载为友元函数的一般形式为:
friend 函数类型 operator 运算符 (参数表 )
{
函数体
}
10.4.2 运算符重载规则
10.4.2 运算符重载规则
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录函数类型指定了重载运算符的返回值类型,operator是定义运算符重载函数的关键字,运算符是 C++中可重载的运算符。当运算符重载为类的成员函数时,双目运算符仅有一个参数,而单目运算符则不能显式的说明参数。
一般情况下,单目运算符最好重载为成员函数,双目运算符最好重载为友元函数,双目运算符重载为友元函数比重载为成员函数更方便操作,但是,有的双目运算符重载为成员函数为好,例如,赋值运算符。如果被重载为友元函数,将会出现与赋值语义不一致的地方。
在 C++中,如果编译器遇到一个表达式或函数的调用使用了一个不合适的数据类型,它经常会类型转换。类型转换是将一种类型的值映射为另一种类型的值。类型转换可分为隐式转换和显式转换两种。
C++编译系统提供的数据类型的隐式转换规则如下:
( 1)程序在执行算术运算时,低类型可以转换为高类型。
( 2)在赋值表达式中,右边表达式的值自动转换为左边变量的类型,并赋值给它。
( 3)在函数调用时,将实参值赋给形参,系统隐式地将实参转换为形参的类型后赋给形参。
( 4)函数有返回值时,系统将自动地将返回的表达式类型转换为函数返回值类型并赋值给该函数。
10.4.3 类型转换与转换函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
1.类型转换
10.4.3 类型转换与转换函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录当在程序中发现两个数据类型不相容时,又不能自动完成隐式转换,则将出现编译错误。
如,int *p = 10;
在这种情况下,为了消除错误,可以进行如下所示的显示类型转换:
int *p = (int*)10; //将整型数 10显式地转换成指针类型
2.转换函数在 C++中,可以通过定义类型转换函数来为用户定义类型达到相同的效果。这些函数有特殊类型的构造函数和重载的运算符。
10.4.3 类型转换与转换函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
1)构造函数转换在实际应用中,当类定义中提供了单个参数的构造函数时,
该类便提供了一种将其他数据类型的数值或变量转换为用户所定义数据类型的方法。因此,可以说单个参数的构造函数提供了数据转换的功能。请看下面的例子:
【 例 10.15】 程序名为 l10_15.cpp。
#include <iostream.h>
class A //定义类 A
{public:
A(double x){m=x;}
void print(){cout<<m<<endl;}
private:
double m;
};
10.4.3 类型转换与转换函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
void main()
{ A a(5);
a=100; //给 A类类型的对象赋值
a.print();
}
在该程序中,赋值语句 a=100,赋值号两边分别是数值 100
和对象 a,两者是不相容的数据类型,可是它却能顺利通过编译程序,并且输出显示正确结果,其主要原因是因为单参数的构造函数。编译系统首先将整型数据 100转换成
double型,然后,再通过类中定义的单参数构造函数将
double型数值转换为 A类类型,最后把它赋值给 a。这些转换都是自动隐式完成的。
10.4.3 类型转换与转换函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
2)运算符转换函数运算符转换方法是通过运算符重载实现的。用户可以创建一个成员函数,这个函数通过在关键字 operatore后跟随想要转换的类型,
将当前类型转换为希望的类型。运算符转换函数又称类型强制转换成员函数,它是类中的一个非静态成员函数。它的定义格式如下:
class 类名称
{ public:
operatore 欲转换的类型(); //转换函数
}
该类中定义了由类类型到欲转换的类型之间的映射关系。需要注意的是,转换函数是用户定义的非静态成员函数,转换函数的名称是类型转换的目标类型,所以转换函数不能有返回值,也不带任何参数,转换函数不能定义为友元函数。请看下面的例子:
10.4.3 类型转换与转换函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
【 例 10.16】 程序名为 l10_16.cpp。
#include <iostream.h>
class R //定义类 R
{public:
R(int w,int l)
{ wid = w;
len = l;
}
operator int(); //声明转换函数
private:
int wid,len;
};
R::operator int() //转换函数的实现
{ return wid*len;
}
void main()
{ R r(5,8);
int s = 8;
s+=r; //整型变量与 R类对象相加
cout<<s<<endl;
}
从程序中我们可以看出,s是一个 int型数值,r是 R类的一个对象,
这两个不同类型的数据之所以能够进行相加,是由于定义了转换函数 operator int()。为了使上述加法能够进行,编译系统先检查类 R的说明,看是否存在转换函数能够将 R类型的操作数转换为 int类型的操作数。由于 R类中说明了转换函数 operator int(),
它可以在程序运行时进行上述类型转换,因此,该程序中实现了 s+=r的操作。程序的输出结果为:
48
10.4.3 类型转换与转换函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
10.5 综合实训创建一个 Point类,用来描述坐标系中的一个点。点具有横坐标和纵坐标两个属性,同时应具有成员函数用来显示点的坐标。再创建一个 Circle类,用来描述坐标系中的一个圆。圆应具有圆心坐标和半径两个属性,还应具有得到圆心坐标和显示圆的属性等相关成员函数。由于圆心是一个点( Point类),所以我们在创建 Circle类的时候可以从
Point类继承。
坐标系中的两个圆有相交、相离和相切三种关系,为了描述这种关系,需要用到圆心坐标之间的距离及两圆半径之和。为了计算方便,我们可以重载,+”运算符返回两圆半径之和;重载,-”运算符返回两点之间的距离。下面是具体的程序实现过程:
【 例 10.17】 程序名为 l10_17.cpp。
#include<iostream.h>
#include<math.h>
class Point //定义 Point类
{private:
double x,y; //私有成员 (点的坐标 )
public:
Point(){} //构造函数
Point(double px,double py) //构造函数
{x=px;y=py;}
void show() //成员函数 (显示坐标 )
{cout<<“(”<<x<<“,”<<y<<“)”;}
friend double operator-(Point p1,Point p2)
{
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
} //“-”运算符重载返回两点之间的距离
};
10.5 综合实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
class Circle:public Point //从 Point类派生 Circle类
{private:
Point p;
double r; //私有成员
public:
Circle(double px,double py,double cr):Point(px,py)
{ //派生类的构造函数
p=Point(px,py);
r=cr;
}
void show() //覆盖基类的成员函数
{ cout<<"[p";
Point::show();
cout<<","<<r<<"]";
}
10.5 综合实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
Point GetCenter() //成员函数 (返回圆心 )
{ return p;}
friend double operator+(Circle c1,Circle c2)
{ return c1.r+c2.r; //“+”运算符重载,返回两圆半径之和
}
};
void Crelation(Circle cr1,Circle cr2)
{ //定义函数说明两圆的关系
if((cr1.GetCenter()-cr2.GetCenter())>(cr1+cr2))
cout<<"两圆相离 "<<endl;
if((cr1.GetCenter()-cr2.GetCenter())==(cr1+cr2))
cout<<"两圆相切 "<<endl;
if((cr1.GetCenter()-cr2.GetCenter())<(cr1+cr2))
cout<<"两圆相交 "<<endl;
}
10.5 综合实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
void main()
{ Point p1(1,1); //定义 Point类对象 p1
Point p2(4,5); //定义 Point类对象 p2
cout<<“p1与 p2两点之间的距离为,”<<endl;
p1.show(); //输出 p1坐标
cout<<“->”;
p2.show(); //输出 p2坐标
cout<<“=”<<p1-p2<<endl; //输出两点之间的距离
Circle c1(0,0,1); //定义 Circle类对象 c1
Circle c2(3,0,2); //定义 Circle类对象 c2
cout<<“c1与 c2两圆圆心之间的距离为,”<<endl;
c1.show(); //输出 c1圆心及半径
cout<<"->";
c2.show(); //输出 c2圆心及半径
10.5 综合实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
cout<<“=”<<c1.GetCenter()-c2.GetCenter()<<endl;
//输出两圆圆心之间的距离
cout<<“两圆的半径之和为,”<<c1+c2<<endl;
cout<<“两圆之间的关系为,”;
Crelation(c1,c2);
}
10.5 综合实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录程序的运行结果如右图: