高级语言 C++程序设计
(第二版)
刘景、周玉龙编第七章 类与对象类,是现实世界中客观事物的抽象,通常将众多的具有相同属性的事物归纳、组合成为某个类。
C++中的类,把数据及对象的操作和处理封装在一个程序模块中,
形成一个整体。(包括数据成员:用于表示属性;成员函数:用于对数据的处理。)
使用类的优点,(P.201.)
程序设计本身更有条理。
程序的可读性更好。
程序设计的过程真正像是机器部件的组装。
程序可由多个程序员设计变得方便和自然。
由于程序的零部件化,使得程序的可重用性变成切实可行的事情。
通过类与对象而实现的面向对象程序设计的三大特征,(P.202.)
封装性
继承性
多态性第七章 类与对象
7.1 设计一个栈类
栈( stack),运算受限的线性表,其运算特点是后进先出。
( LIFO)
两个数据成员,
float data[maxsize];
int top;
三个成员函数 (对应着 ):
void push(float a);//将一个数据,压入,栈顶。
float pop(void);//将栈顶的数据,弹出,返回。
bool empty(void);//判断当前栈是否为空(栈)。
//program 7-1.cpp
//inlcude<iostream.h>
const int maxsize=6;
第七章 类与对象
class stack
{
float data[maxsize];
int top;
public:
stack(void); //构造函数
~stack(void);//析构函数
bool empty(void);
void push(float a);
float pop(void);
};
stack::stack(void){
top=0;
cout<<“stack initialize.”<<endl;
}
第七章 类与对象
stack::~stack(void) {
cout<<“stack destroyed”<<endl;
}
bool stack::empty(void){
return top==0;
}
void satck::push(float a){
if(top==maxsize){
cout<<“Stack overflow!”<<endl;
return;
}
data[top]=a;
top++;
}
第七章 类与对象
float stack::pop(void) {
if(top==0){
cout<<“An empty stack!”<<endl;
return 0;
}
top--;
return data[top];
}
void main(){
stack s1,s2;
for(int i=1;i<=maxsize;i++)
s1.push(2*i);
for(i=1;i<=maxsize;i++)
cout<<s1.pop()<<“,;
第七章 类与对象
void main(){
stack s1,s2;
for(int i=1;i<=maxsize;i++)
s1.push(2*i);
for(i=1;i<=maxsize;i++)
cout<<s1.pop()<<“,;
for(i=1;i<=maxsize;i++)
s1.push(2.5*i);
for(i=1;i<=maxsize;i++)
s2.push(s1.pop());
cout<<endl;
do
cout<<s2.pop()<<“,;
while(!(s2.empty()));
cout<<endl;}
第七章 类与对象
7.2 类和对象的说明
一个类说明的常用格式为,
class <自定义类类型名 >
{
private:
<各私有成员说明 >;
public:
<各公有成员说明 >;
};
类成员分为,数据成员和成员函数。
注,类的成员函数定义,既可以放在类定义体内,也可以放在类定义体外。如果放在外面,要用,<类名 >::” 来限定。(放在类体外定义时,类体内必须有其函数原型。)
类对象的声明方式,(类对象也称:类变量或类的实例)
<类名 > <对象名 1>,…,<对象名 n>
第七章 类与对象
对象成员(数据成员和成员函数)的访问方式,
<对象名 >.<成员名 >
说明,若在该类的说明中含有带参数的构造函数,则在说明对象的同时,要给出具体的实参初始化对象。
<类名 > <对象名 1>(实参表 1),…,<对象名 n>(实参表 n)
注,可以说明类对象的数组以及指向对象的指针;同类型的对象之间可以相互赋值;对象可作为函数的参数;函数的返回值可以是类对象;类的成员可以是对象成员。
示例程序,
//program 7-2.cpp
#include<iostream.h>
class point{
private:
float xcoord,ycoord;
public:
第七章 类与对象
public:
float getx(){return xcoord;}
//注意:函数体中的 return语句也可以改写为
//,return (*this).xcoord;”或,return this->xcoord;”
float gety();
void setx(float x){xcoord=x;}
void sety(float y);
ovid display(){cout<<“xcoord=”<<xcoord<<endl;}
void display(){cout<<“ycoord=”<<ycoord<<endl;}
};
float point::gety(){return ycoord;}
void point::sety(float y){ycoord=y;}
void main(){
point obj1,*p,objArr[6];
obj.setx(123.5);
第七章 类与对象
//cout<<obj1.xcoord<<endl;
//出错!在 main中,不可通过对象来访问类的 private私有成员
cout<<obj1.getx()<<endl;
obj1.displayx();
p=new point;
(*p).setx(5.6);
p->sety(7.8);
float k=(*p).getx();
float m=p->gety();
cout<<“k=”<<k<<endl;
cout<<“m=”<<m<<endl;
for(int i=0;i<3;i++){
objArr[i].setx(i+10.1);
objArr[i].sety(i+20.2);}
第七章 类与对象
p=&objArr[5];
while(p>=&objArr[3]){
p->setx(88.8);
p->sety(99.9);
p--;
}
for(i=0;i<6;i++)
cout<<objArr[i].getx()<<,”<<objArr[i].gety()<<endl;
}
7.3 对象的初始化、构造与析构函数
7.3.1 基本概念及定义
1、公有数据成员初始化
(与一般变量、结构变量、数组等初始化类似。 )
第七章 类与对象
class address{
public:
long telenum;
char addr[30];
};
class person{
public:
char name[15];
int age;
address paddr;
};
person p1={“Zhang Hua”,23,{2475096,”NanKai University”}};
2、公有的初始化函数(专门设计一个初始化函数,P.210.)
第七章 类与对象
3、构造函数(可以有一个或多个)
函数名与类名相同。
无函数(返回)类型说明。
构造函数在一个新的对象被建立时,该对象所隶属类的构造函数自动地被调用,对这个对象完成初始化工作。
新对象建立包括两种情况:在对象说明语句中;用 new建立新的动态对象时。
如果一个类说明中没有给出显式的构造函数,系统将自动给出一个缺省
(隐式的)构造函数,<类名 >(void){}
如果说明中包括多个构造函数,一般它们有不同的参数表和函数体。
4、析构函数(专门用来在对象的生存期结束时使用。 P.211)
析构函名一律为 ~< 类名 >。
无函数返回类型。
无参数。
一个类只可有一个析构函数,也可以缺省。
在对象注销时,包括用 delete函数释放动态对象时,系统自动调用析构函数。
第七章 类与对象
若某个类定义中没有给出显式的析构函数,则系统自动给出一个缺省的
(隐式的)析构函数,~<类名 >(void){}
7.3.2 构造与析构函数使用示例
//program 7-3.cpp
#include<iostream.h>
#include<string.h>
class String{
char *text;
public:
String(char *str);
~String();
void printStr(){cout<<text<<endl;}
};
String::String(char *str){
cout<<“enter?String::String?,str=>”<<str<<endl;
第七章 类与对象
String::String(char *str){
cout<<“enter?String::String?,str=>”<<str<<endl;
text=new char[strlen(str)+1];
strcpy(text,str);
}
String::~String(){
cout<<“enter?String::~String?,str=>”<<text<<endl;
delete []text;
}
void main(){
String str1(“a1d11”);
String str2(“a2d22”);
str1.printStr();
str2.printStr();
cout<<“ending main!”<<endl;}
第七章 类与对象
7.4 类的定义及其使用
7.4.1 创建一个集合类型 (P.213~218.)
7.4.2 利用 stack类型解迷宫问题 (P.218~224.)
7.5 类的静态成员及常量成员
7.5.1 类的静态成员
静态成员,由关键字 static修饰的类成员称为类的静态成员。
1、静态数据成员 (P.224.)
注,类的静态数据成员,其数据将被该类的所有对象所共享。(在类中说明的静态数据成员属于 引用性 说明,即还必须在类外文件作用域中的某个地方对静态数据员按如下格式进行 定义性 说明:
<类型 > <类名 >::<静态数据成员 >=<初值 >)
访问静态成员的方式,<类名 >::<静态数据成员名 >
示例,参见 //program7-6.cpp,P.226.
2、静态函数成员 (P.225.)
第七章 类与对象
2、静态函数成员 (P.225.)
注,静态函数成员没有 this指针。
调用方式,<类名 >::<静态函数成员调用 >
3、静态成员使用示例( P.226.)
7.5.2 类的常量成员
1、常量数据成员 (P.227.)
注,通过关键字 const修饰的类的数据成员。(它不同于一般的符号常量,在成员说明时不能被赋值,而只能在对象说明时通过构造函数的成员初始化列表的方式来赋初值。)
例如:
class CC{
int i;
const int c1;
public:
const int c2;
第七章 类与对象
CC(int a,int b):c1(a),c2(b){
i=c1;
}
…
};
在类外说明 CC类对象时,CC cobj(4,7)。
cobj的成员 c1,c2,i的值分别为,4,7,4。
2、常量函数成员 (P.228.)
注,常量类型的函数成员,只有权读取相应对象的内容,但无权修改它们。
说明格式,<类型 > <函数名 >(<参数表 >) const {… }
7.6 友元
定义友元的关键字,friend
第七章 类与对象
类 A的友元函数,
它不是类 A的函数成员。
可以在类 A内说明,也可以在类 A外说明。
它有权访问和调用类 A的所有私有及保护成员。
类 A的友元类 B:
它可能是与 A无关的另外一个类。
要在类外说明。
B的任何一函数都有权访问和调用类 A的所有成员,包括私有及保护成员。
类 A的友元函数和类 A的成员函数的区别,类 A的友元函数在访问类 A
的成员时,必须显式调用(即通过类对象调用);而类 A的成员函数在访问类 A的成员时,可以直接调用(即通过 this指针调用)。
示例,( P.210~232.)
7.7 类之间的关系第七章 类与对象
C++中类和对象之间联系的方式有,
一个类的对象作为另一个类的成员。
一个类的成员函数作为另一个类的友元。
一个类定义在另一个类的说明中,即类的嵌套。
一个类作为另一个类的派生类。
1、类对象成员
注意成员的初始化,一般由构造函数的成员初始化表来给出。
示例 (P.233.)
2、类的嵌套
一个类的说明包含在另一个类的说明中。
在一个类中嵌套的私有类和公有类的访问区别( P.234.)
7.8 自定义类中的运算符重载 (P.235.)
第七章 类与对象
7.8.1 以两种方式对运算符进行重载
自定义类中运算符重载的两种方式,
类成员方式(把运算符的重载,作为类的成员函数)。
友元方式(把类的运算符重载,作为类的友元函数)。
两种重载方式的参数比较
以友元方式重载时,参数个数和运算量个数相同。
以类成员方式重载时,参数个数比运算量个数少一个。(其中一个参数为调用对象的 this指针,被隐藏了)
示例:
友元方式重载示例。( P.236~237.)
类成员方式重载示例( P.237.)
7.8.2 利用运算符重载实现集合类型( P.238~243.)
(第二版)
刘景、周玉龙编第七章 类与对象类,是现实世界中客观事物的抽象,通常将众多的具有相同属性的事物归纳、组合成为某个类。
C++中的类,把数据及对象的操作和处理封装在一个程序模块中,
形成一个整体。(包括数据成员:用于表示属性;成员函数:用于对数据的处理。)
使用类的优点,(P.201.)
程序设计本身更有条理。
程序的可读性更好。
程序设计的过程真正像是机器部件的组装。
程序可由多个程序员设计变得方便和自然。
由于程序的零部件化,使得程序的可重用性变成切实可行的事情。
通过类与对象而实现的面向对象程序设计的三大特征,(P.202.)
封装性
继承性
多态性第七章 类与对象
7.1 设计一个栈类
栈( stack),运算受限的线性表,其运算特点是后进先出。
( LIFO)
两个数据成员,
float data[maxsize];
int top;
三个成员函数 (对应着 ):
void push(float a);//将一个数据,压入,栈顶。
float pop(void);//将栈顶的数据,弹出,返回。
bool empty(void);//判断当前栈是否为空(栈)。
//program 7-1.cpp
//inlcude<iostream.h>
const int maxsize=6;
第七章 类与对象
class stack
{
float data[maxsize];
int top;
public:
stack(void); //构造函数
~stack(void);//析构函数
bool empty(void);
void push(float a);
float pop(void);
};
stack::stack(void){
top=0;
cout<<“stack initialize.”<<endl;
}
第七章 类与对象
stack::~stack(void) {
cout<<“stack destroyed”<<endl;
}
bool stack::empty(void){
return top==0;
}
void satck::push(float a){
if(top==maxsize){
cout<<“Stack overflow!”<<endl;
return;
}
data[top]=a;
top++;
}
第七章 类与对象
float stack::pop(void) {
if(top==0){
cout<<“An empty stack!”<<endl;
return 0;
}
top--;
return data[top];
}
void main(){
stack s1,s2;
for(int i=1;i<=maxsize;i++)
s1.push(2*i);
for(i=1;i<=maxsize;i++)
cout<<s1.pop()<<“,;
第七章 类与对象
void main(){
stack s1,s2;
for(int i=1;i<=maxsize;i++)
s1.push(2*i);
for(i=1;i<=maxsize;i++)
cout<<s1.pop()<<“,;
for(i=1;i<=maxsize;i++)
s1.push(2.5*i);
for(i=1;i<=maxsize;i++)
s2.push(s1.pop());
cout<<endl;
do
cout<<s2.pop()<<“,;
while(!(s2.empty()));
cout<<endl;}
第七章 类与对象
7.2 类和对象的说明
一个类说明的常用格式为,
class <自定义类类型名 >
{
private:
<各私有成员说明 >;
public:
<各公有成员说明 >;
};
类成员分为,数据成员和成员函数。
注,类的成员函数定义,既可以放在类定义体内,也可以放在类定义体外。如果放在外面,要用,<类名 >::” 来限定。(放在类体外定义时,类体内必须有其函数原型。)
类对象的声明方式,(类对象也称:类变量或类的实例)
<类名 > <对象名 1>,…,<对象名 n>
第七章 类与对象
对象成员(数据成员和成员函数)的访问方式,
<对象名 >.<成员名 >
说明,若在该类的说明中含有带参数的构造函数,则在说明对象的同时,要给出具体的实参初始化对象。
<类名 > <对象名 1>(实参表 1),…,<对象名 n>(实参表 n)
注,可以说明类对象的数组以及指向对象的指针;同类型的对象之间可以相互赋值;对象可作为函数的参数;函数的返回值可以是类对象;类的成员可以是对象成员。
示例程序,
//program 7-2.cpp
#include<iostream.h>
class point{
private:
float xcoord,ycoord;
public:
第七章 类与对象
public:
float getx(){return xcoord;}
//注意:函数体中的 return语句也可以改写为
//,return (*this).xcoord;”或,return this->xcoord;”
float gety();
void setx(float x){xcoord=x;}
void sety(float y);
ovid display(){cout<<“xcoord=”<<xcoord<<endl;}
void display(){cout<<“ycoord=”<<ycoord<<endl;}
};
float point::gety(){return ycoord;}
void point::sety(float y){ycoord=y;}
void main(){
point obj1,*p,objArr[6];
obj.setx(123.5);
第七章 类与对象
//cout<<obj1.xcoord<<endl;
//出错!在 main中,不可通过对象来访问类的 private私有成员
cout<<obj1.getx()<<endl;
obj1.displayx();
p=new point;
(*p).setx(5.6);
p->sety(7.8);
float k=(*p).getx();
float m=p->gety();
cout<<“k=”<<k<<endl;
cout<<“m=”<<m<<endl;
for(int i=0;i<3;i++){
objArr[i].setx(i+10.1);
objArr[i].sety(i+20.2);}
第七章 类与对象
p=&objArr[5];
while(p>=&objArr[3]){
p->setx(88.8);
p->sety(99.9);
p--;
}
for(i=0;i<6;i++)
cout<<objArr[i].getx()<<,”<<objArr[i].gety()<<endl;
}
7.3 对象的初始化、构造与析构函数
7.3.1 基本概念及定义
1、公有数据成员初始化
(与一般变量、结构变量、数组等初始化类似。 )
第七章 类与对象
class address{
public:
long telenum;
char addr[30];
};
class person{
public:
char name[15];
int age;
address paddr;
};
person p1={“Zhang Hua”,23,{2475096,”NanKai University”}};
2、公有的初始化函数(专门设计一个初始化函数,P.210.)
第七章 类与对象
3、构造函数(可以有一个或多个)
函数名与类名相同。
无函数(返回)类型说明。
构造函数在一个新的对象被建立时,该对象所隶属类的构造函数自动地被调用,对这个对象完成初始化工作。
新对象建立包括两种情况:在对象说明语句中;用 new建立新的动态对象时。
如果一个类说明中没有给出显式的构造函数,系统将自动给出一个缺省
(隐式的)构造函数,<类名 >(void){}
如果说明中包括多个构造函数,一般它们有不同的参数表和函数体。
4、析构函数(专门用来在对象的生存期结束时使用。 P.211)
析构函名一律为 ~< 类名 >。
无函数返回类型。
无参数。
一个类只可有一个析构函数,也可以缺省。
在对象注销时,包括用 delete函数释放动态对象时,系统自动调用析构函数。
第七章 类与对象
若某个类定义中没有给出显式的析构函数,则系统自动给出一个缺省的
(隐式的)析构函数,~<类名 >(void){}
7.3.2 构造与析构函数使用示例
//program 7-3.cpp
#include<iostream.h>
#include<string.h>
class String{
char *text;
public:
String(char *str);
~String();
void printStr(){cout<<text<<endl;}
};
String::String(char *str){
cout<<“enter?String::String?,str=>”<<str<<endl;
第七章 类与对象
String::String(char *str){
cout<<“enter?String::String?,str=>”<<str<<endl;
text=new char[strlen(str)+1];
strcpy(text,str);
}
String::~String(){
cout<<“enter?String::~String?,str=>”<<text<<endl;
delete []text;
}
void main(){
String str1(“a1d11”);
String str2(“a2d22”);
str1.printStr();
str2.printStr();
cout<<“ending main!”<<endl;}
第七章 类与对象
7.4 类的定义及其使用
7.4.1 创建一个集合类型 (P.213~218.)
7.4.2 利用 stack类型解迷宫问题 (P.218~224.)
7.5 类的静态成员及常量成员
7.5.1 类的静态成员
静态成员,由关键字 static修饰的类成员称为类的静态成员。
1、静态数据成员 (P.224.)
注,类的静态数据成员,其数据将被该类的所有对象所共享。(在类中说明的静态数据成员属于 引用性 说明,即还必须在类外文件作用域中的某个地方对静态数据员按如下格式进行 定义性 说明:
<类型 > <类名 >::<静态数据成员 >=<初值 >)
访问静态成员的方式,<类名 >::<静态数据成员名 >
示例,参见 //program7-6.cpp,P.226.
2、静态函数成员 (P.225.)
第七章 类与对象
2、静态函数成员 (P.225.)
注,静态函数成员没有 this指针。
调用方式,<类名 >::<静态函数成员调用 >
3、静态成员使用示例( P.226.)
7.5.2 类的常量成员
1、常量数据成员 (P.227.)
注,通过关键字 const修饰的类的数据成员。(它不同于一般的符号常量,在成员说明时不能被赋值,而只能在对象说明时通过构造函数的成员初始化列表的方式来赋初值。)
例如:
class CC{
int i;
const int c1;
public:
const int c2;
第七章 类与对象
CC(int a,int b):c1(a),c2(b){
i=c1;
}
…
};
在类外说明 CC类对象时,CC cobj(4,7)。
cobj的成员 c1,c2,i的值分别为,4,7,4。
2、常量函数成员 (P.228.)
注,常量类型的函数成员,只有权读取相应对象的内容,但无权修改它们。
说明格式,<类型 > <函数名 >(<参数表 >) const {… }
7.6 友元
定义友元的关键字,friend
第七章 类与对象
类 A的友元函数,
它不是类 A的函数成员。
可以在类 A内说明,也可以在类 A外说明。
它有权访问和调用类 A的所有私有及保护成员。
类 A的友元类 B:
它可能是与 A无关的另外一个类。
要在类外说明。
B的任何一函数都有权访问和调用类 A的所有成员,包括私有及保护成员。
类 A的友元函数和类 A的成员函数的区别,类 A的友元函数在访问类 A
的成员时,必须显式调用(即通过类对象调用);而类 A的成员函数在访问类 A的成员时,可以直接调用(即通过 this指针调用)。
示例,( P.210~232.)
7.7 类之间的关系第七章 类与对象
C++中类和对象之间联系的方式有,
一个类的对象作为另一个类的成员。
一个类的成员函数作为另一个类的友元。
一个类定义在另一个类的说明中,即类的嵌套。
一个类作为另一个类的派生类。
1、类对象成员
注意成员的初始化,一般由构造函数的成员初始化表来给出。
示例 (P.233.)
2、类的嵌套
一个类的说明包含在另一个类的说明中。
在一个类中嵌套的私有类和公有类的访问区别( P.234.)
7.8 自定义类中的运算符重载 (P.235.)
第七章 类与对象
7.8.1 以两种方式对运算符进行重载
自定义类中运算符重载的两种方式,
类成员方式(把运算符的重载,作为类的成员函数)。
友元方式(把类的运算符重载,作为类的友元函数)。
两种重载方式的参数比较
以友元方式重载时,参数个数和运算量个数相同。
以类成员方式重载时,参数个数比运算量个数少一个。(其中一个参数为调用对象的 this指针,被隐藏了)
示例:
友元方式重载示例。( P.236~237.)
类成员方式重载示例( P.237.)
7.8.2 利用运算符重载实现集合类型( P.238~243.)