C++程序设计 湖南大学 杜四春、银红霞
第 8章 类和对象
8.1 类和对象
8.2 类对象
8.3 构造函数和析构函数
8.4 类的初始化
8.5 复杂的对象表示
8.6 堆与拷贝构造函数
8.7 this指针
8.8 引用
8.9 常类型
C++程序设计 湖南大学 杜四春、银红霞
类构成了实现 C++面向对象程序设计的基
础,在 C++语言面向对象程序设计中占据着核
心地位。它把数据和作用在这些数据上的操作
组合在一起,是封装的基本单元。对象是类的
实例,类定义了属于该类的所有对象的共同特
性。
C++程序设计 湖南大学 杜四春、银红霞
8.1 类和对象
从一般意义上讲, 对象 ( Object) 是现实
世界中的客观事物 。 类是把具有相同属性的事
物划分为一类, 从而得出的抽象概念 。 类是一
组性质相同的对象的程序描述, 它由概括了一
组对象共同性质的数据和函数组成 。
面向对象的程序设计中最基本的概念是对
象,一般意义上的对象指的是一个实体的实例,
在这个实体中包括了特定的数据和对这些数据
进行操作的函数。对象的核心概念就是通常所
说的“封装性”( encapsulation)、“继承性”
( inheritance)和“多态性”
( polymorphism)。
C++程序设计 湖南大学 杜四春、银红霞
8.1.1 类的定义
类是一种用户自定义的数据类型, 它的一般定义
格式如下:
class <类名 >
{
private:
<私有数据成员和成员函数 >;
protected:
<保护数据成员和成员函数 >;
public:
<公有数据成员和成员函数 >;
}
<各个成员函数的实现 >;
C++程序设计 湖南大学 杜四春、银红霞
其中,class是定义类的关键字。 <类名 >是一个标
识符,用于惟一标识一个类。一对大括号内是类的说
明部分,说明该类的所有成员。类的成员包括数据成
员和成员函数两部分。类的成员从访问权限上分有以
下三类:公有的( public)、私有的( private)和保护
的( protected),其中默认为 private权限。说明为公
有的成员可以被程序中的任何代码访问;说明为私有
的成员只能被类本身的成员函数及友元类的成员函数
访问,其他类的成员函数,包括其派生类的成员函数
都不能访问它们;说明为保护的成员与私有成员类似,
只是除了类本身的成员函数和说明为友元类的成员函
数可以访问保护成员外,该类的派生类的成员也可以
访问。
C++程序设计 湖南大学 杜四春、银红霞
例 8-1:
include <iostream.h>
class Sample
{
int x,y;
public:
Sample() {x=y=0;}
Sample(int a,int b) {x=a;y=b;}
Void disp()
{
cout<<”x=”<<x<<”,y=”<<y<<endl;
}
};
void main()
{
Sample s1,s2(1,2);
s1.disp();
s2.disp();
}
此程序的运行结果为:
x=0,y=0
x=1,y=2
C++程序设计 湖南大学 杜四春、银红霞
8.1.2 类的成员函数
定义类的函数成员的格式如下:
返回类型 类名,:成员函数名 ( 参数说明 )
{
函数体
}
类的成员函数对类的数据成员进行操作,成员函
数的定义体可以在类的定义体中,如例 8-2所示。
C++程序设计 湖南大学 杜四春、银红霞
例 8-2:类中的成员函数在类定义中直接描述示例 。
class Location {
public:
void init(int x,int y)
{
X=x;
Y=y;
}
private:
int X,Y;
public:
int GetX()
{ return X; }
int GetY()
{ return X; }
}
C++程序设计 湖南大学 杜四春、银红霞
类的成员函数也可以另外定义, 而在类定义时给
出函数头 。
例 8-2的成员函数可说明如下:
void Location::init(int x,int y)
{
X=x;
Y=y;
}//将 x,y的值分别赋给 X,Y
int Location::GetX()
{
return X;
}
int Location::GetY()
{
return Y;
}
C++程序设计 湖南大学 杜四春、银红霞
一个类的说明可分为定义性说明和引用性说明两
种, 引用性说明仅说明类名 。 例如,class Location;
引用性说明不能用于说明类的变量, 但可说明指
针, 例如,class myClass{
private:
int i;
myclass member;//错
myclass *pointer;//对
}
注意:在类定义体外定义成员函数时,需在函数
名前加上类域标记,因为类的成员变量和成员函数属
于所在的类域,在域内使用时,可直接使用成员名字,
而在域外使用时,需在成员名外加上类对象的名称。
C++程序设计 湖南大学 杜四春、银红霞
8.1.3 类和结构
结构是类的一种特例, 在结构中也可以定义成员
函数 。 定义结构时只要把关键字 class 改为 struct即可 。
class Location {
private:
int X,Y;
public:
void init(int x,int y)
{
X=x;
Y=y;
}
int GetX()
{ return X; }
int GetY()
{ return Y; }
}
C++程序设计 湖南大学 杜四春、银红霞
结构和类的唯一区别是:在未指定访问权限时,
结构中的成员被默认为公有的而类中的成员被默认为
私有的 。 在所有其他方面, 类和结构等价 。 例如:
struct S
{
int X;//公有的
...
}
class C
{
int X;//私有的
...
}
尽管类和结构是等
价的,但一般在描述数
据时使用结构,在描述
数据及对数据的操作时
用类。
C++程序设计 湖南大学 杜四春、银红霞
由于类和结构是等价的, 对类的五种操作对结构
也同样适用:
( 1) 对象之间可以相互赋值 。
Location locationA,locationB;
locationA.init(5,6);
locationB=locationA;
locationB的数据成员和 locationA的数据成员有相同
的值 。
( 2) 对象可以作为数组的元素 。
Location arrayloc[100];
arrayloc是以结构 Location为元素的数组。
C++程序设计 湖南大学 杜四春、银红霞
( 3) 可以说明指向对象的指针, 但不能取私有数
据成员的指针或成员函数的地址 。
Location location;
Location *pointLoc=&location;
当 pointLoc被加 1后, 它将指向下一个 Location对
象 。
( 4) 对象可以作为函数的参数, 既可作值参 ( 不
影响实参 ), 也可以作引用参数 。
void display(Location &location)
{,.,};
location就是引用参数。
C++程序设计 湖南大学 杜四春、银红霞
( 5) 一个对象可以是另一个对象的成员 。
例如:可以定义 一个 Rectangle 类, 含有 一个
Location结构类型的成员 。
H=h;
W=w; }
Location *GetLoc() { return &Loc; }
int GetH() { return H; }
int GetW() { return W; }
}
class Rectangle {
Location Loc;
int H,W;
public:
void init(int x,int y,int h,int w)
{
Loc.init(x,y);
C++程序设计 湖南大学 杜四春、银红霞
8.2 类对象
为了使用类, 还必须说明类的对象 。 在定义类时,
系统是不会给类分配存储空间的, 只有定义类对象时
才会给对象分配相应的内存空间 。
8.2.1 对象的定义格式
定义类对象的格式如下:
<类名 ><对象名表 >;
其中,<类名 >是待定的对象所属的类的名字,即
所定义的对象是该类的对象。 <对象名表 >中可以有一
个或多个对象名,多个对象名用逗号分隔。在 <对象名
>中,可以是一般的对象名,还可以是指向对象的指针
名或引用名,也可以是对象数组名。
C++程序设计 湖南大学 杜四春、银红霞
8.2.2 对象成员的表示方法
一个对象的成员就是该对象的类所定义的成员 。
对象成员有数据成员和成员函数 。 一般对象的成员表
示如下:
<对象名 >.<成员名 >
或者
<对象名 >.<成员名 >( <参数表 >)
前者用于表示数据成员, 后者用于表示成员函数 。
这里的,,”是一个运算符, 该运算符的功能是表示对象
的成员 。
C++程序设计 湖南大学 杜四春、银红霞
指向对象的指针的成员表示如下:
<对象指针名 >-><成员名 >
或者
<对象指针名 >-><成员名 >( <参数表 >)
同样,前者用于表示数据成员,后者用于表示成
员函数。这里的, ->”是一个表示成员的运算符,它与
前面介绍过的,,”运算符的区别是:, ->”用来表示指
向对象的指针的成员,而,,”用来表示一般对象的成员。
对于数据成员和成员函数, 以下两种表示方式是
等价的:
<对象指针名 >-><成员名 >

( *<对象指针名 >),<成员名 >
C++程序设计 湖南大学 杜四春、银红霞
8.3 构造函数和析构函数
构造函数和析构函数都是类的成员函数,
但它们是特殊的成员函数, 不用调用便自动执
行, 而且这些函数的名字与类的名字有关 。
8.3.1 构造函数
构造函数是一种用于创建对象特殊的成员函数,
当创建对象时, 系统自动调用构造函数, 不能在程序
中直接调用 。 构造函数名与类名相同, 一个类可以拥
有多个构造函数 ( 重载 ), 构造函数可以有任意类型
的参数, 但不能具有返回类型 。
构造函数的作用是:为对象分配空间;对数据成
员赋初值;请求其他资源。
C++程序设计 湖南大学 杜四春、银红霞
如果一个类没有定义构造函数, 编译器会自动生
成一个不带参数的默认构造函数, 其格式如下:
<类名 >::<默认构造函数名 >( )
{
}
在程序中定义一个对象而没有指明初始化时,编
译器便按默认构造函数来初始化该对象。
C++程序设计 湖南大学 杜四春、银红霞
8.3.2 析构函数
当一个对象消失, 或用 new创建的对象用 delete删
除时, 由系统自动调用类的析构函数 。 析构函数名字
为符号, ~”加类名, 析构函数没有参数和返回值 。 一
个类中只可能定义一个析构函数, 所以析构函数不能
重载 。
析构函数是用于取消对象成员函数, 当一个对象
作用域结束时, 系统自动调用析构函数 。
析构函数的作用是进行清除对象, 释放内存等 。
当对象超出其定义范围时 ( 即释放该对象时 ),
编译器自动调用析构函数 。 在以下情况下, 析构函数
也会被自动调用:
C++程序设计 湖南大学 杜四春、银红霞
( 1) 如果一个对象被定义在一个函数体内, 则当
这个函数结束时, 该对象的析构函数被自动调用 。
( 2)若一个对象是使用 new运算符动态创建的,
在使用 delete运算符释放它时,delete将会自动调用析
构函数。
如同默认构造函数一样, 如果一个类没有定义析
构函数, 编译器会自动生成一个默认析构函数, 其格
式如下:
<类名 >::~<默认析构函数名 >( )
{
}
默认析构函数是一个空函数。
C++程序设计 湖南大学 杜四春、银红霞
8.3.3 带参数的构造函数
带参数的构造函数可以在创建对象时,用具体数
值初始化数据成员和各种数据元素。
注意:构造函数的参数个数和类型规定了声明一
个对象时, 为对这个对象进行初始化所需要的初始值
的个数和类型 。
例如:
Location A (100,200) ; // OK
Location B (10) ; // error
Location A ; // error
若有多个重载构造函数,系统自动寻找匹配。
C++程序设计 湖南大学 杜四春、银红霞
8.3.4 重载构造函数
构造函数可以像普通函数一样被重载,C++根据
说明中的参数个数和类型选择合适的构造函数。若类
X 具有一个或多个构造函数,创建类 X 的对象时,
C++会根据参数选择调用其中一个。
构造函数可以使用默认参数,但谨防二义性。
使用构造函数的限制:不能被继承, 不能说明为
虚函数, 不能显式调用, 不能取构造函数的地址 。
C++程序设计 湖南大学 杜四春、银红霞
无论何时,创建对象时都要调用构造函数(包括
默认构造函数)。构造函数的工作是建立对象的基本
结构,进行数据初始化。即:初始化虚函数表;建立
基类对象;建立非静态数据成员对象;安置虚基类对
象信息;执行构造函数体中的代码。
当一个对象退出其作用域时,都要调用析构函数。
析构函数的工作是:执行析构函数中的代码,将对象
占据的存储空间归还系统,做公共及用户要求的善后
工作。
C++程序设计 湖南大学 杜四春、银红霞
8.4 类的初始化
1,C++允许以下 3 种数据初始化方法:
( 1) 初始值表:适用于结构和数组的初始化 。
例如:
struct conf
{ char *month; int day; int year;
} cpp[ ]={“Nov.”,12,1998,
“Oct.”,8,1999,
“April”,6,2000
}
C++程序设计 湖南大学 杜四春、银红霞
( 2) 赋值表达式:适用于简单变量或指针类型的
初始化 。
例如:
int i = 1 ;
char *p =,No,1” ;
( 3) 表达式表:与方法 ( 2) 语义相同, 风格不
一样 。
例如:
int i (1) ;
char *p (,No,1” ) ;
构造函数的初始化主要采用表达式表的方法 。
C++程序设计 湖南大学 杜四春、银红霞
2,C++中, 类的初始化分为两种情况:
( 1) 对仅有公有段成员, 而没有构造函数或基类的类对
象, 用初始值表来表示 。 典型例子是结构 。
( 2)带有构造函数的类的初始化。
例如:
class X
{ public:
X ( ) ;
X ( int i ) ;
private:
int i ;
};
main ( )
{ X one ; // 调用无参构造函数 X::X()
X two (1) ; // 调用构造函数 X::X(int),
// 表达式表
X three = 1 ; // 调用构造函数 X::X(int),
// 赋值表达式
}
C++程序设计 湖南大学 杜四春、银红霞
3,初始化时, 构造函数可用两种方式把值赋给
成员,
( 1) 接受该值作为参量, 并在构造函数体内赋给
其成员 。
例如:
class X
{ int a,b ; // 默认为 private 成员
public:
X( int i,int j )
{ a = i ; b = j ; }
}
C++程序设计 湖南大学 杜四春、银红霞
( 2) 使用函数体前的初值表 ( 冒号语法 ) 。
例如:代替函数体内对一般成员赋值示例 。
class X
{ int a,b ;
public:
X( int i,int j ), a ( i ), b ( j ) { };
}
C++程序设计 湖南大学 杜四春、银红霞
8.5 复杂的对象表示
1,类类型的常量
基本类型常量直接由其书写形式表示它的值和类
型, 例如:
1.2 12e3 double 类型的常量
102 45 int 类型的常量
’ a’ ’b’ char 类型的常量
形式上, 类类型不存在像基本类型那样的常量,
但有些类类型确实存在常量 。 例如, 说明一个复数类
Complex,以下都是数学上的复数类常量:
2 + 3i 23 + 0i
C++程序设计 湖南大学 杜四春、银红霞
说明复数类 Complex:
class Complex
{ int Rem ; int Imp ;
public:
Complex ( int ) { Rem = a ; Imp = 0 ; }
Complex ( int a,int b ) { Rem = a ; Imp = b ; }
...
} ;
...
Complex x = Complex ( 2,3 );
Complex y = Complex ( 23 );
...
构造函数用于类型转换:带
参数的构造函数将基本类型
常量转换成 Complex常量。
( 2,3 )==,2 + 3i
23 ==,23 + 0i
C++程序设计 湖南大学 杜四春、银红霞
2,类对象作为成员
C++中, 类对象常常可以作为另一个类的成员 。
3,对象的数组
C++中, 可以创建对象数组 。 为了创建对象数组,
构造函数的形式必须是:
( 1) 使用默认构造函数;
( 2) 若有用户自定义构造函数, 则必须含有一个
不带参数或具有一个带默认参数的构造函数 。
C++程序设计 湖南大学 杜四春、银红霞
4,对象指针
对象指针在 C++中很重要, 对象可以直接引用,
也可以通过对象指针来引用 。
注意:当指针加 1或减 1时,它的增加或减少方式
会使指针指向其基类型的下一元素或上一元素。
5,对象参数传递到函数
对象可以作参数传递到函数:传值方式和传地址
方式。
C++程序设计 湖南大学 杜四春、银红霞
8.6 堆与拷贝构造函数
8.6.1 堆对象
1,C++程序的内存布局
C++程序的内存格局通常分为四个区:
( 1) 全局数据区 (data area)
存放全局变量, 静态数据, 常量 。
( 2) 代码区 (code area)
存放类成员函数, 其他函数代码 。
( 3) 栈区 (stack area)
存放局部变量, 函数参数, 返回数据, 返回地址 。
( 4) 堆区 (heap area) 。
自由存储区。
C++程序设计 湖南大学 杜四春、银红霞
2,堆对象
堆对象是在程序运行时根据需要随时可以被创建
或删除的对象,当创建堆对象时,堆中的一个存储单
元从未分配状态变为已分配状态,当删除堆对象时,
存储单元从分配状态又变为未分配状态,可供其他动
态数据使用。
C++程序设计 湖南大学 杜四春、银红霞
8.6.2 new 和 delete
与对基本数据类型操作一样, new 和 delete算符
可以用于创建和删除堆对象 。
语法:
new T ( 初始值 )
创建一个 T类型对象, 返回值为对象首地址
new T [ E ]
创建一个 T类型对象数组, 返回值为数组首地址
delete 指针变量
删除一个指针变量所指的对象
delete [ ] 指针变量
删除一个指针变量所指的对象数组
其中 T 是类型, E 是算术表达式
C++程序设计 湖南大学 杜四春、银红霞
8.6.3 拷贝构造函数
1,拷贝构造函数的表示
当构造函数的参数为自身类的引用时, 这个构造
函数称为拷贝构造函数 。 拷贝构造函数的功能是用一
个已有对象初始化一个正在建立的同类对象 。 例如:
class A {
public,
A( int ) ;
A ( const A &,int = 1 ) ;

};

A a ( 1 ) ;
A b ( a,0 ) ;
A c = b ;
C++程序设计 湖南大学 杜四春、银红霞
2,拷贝构造函数的执行
( 1)用已有对象初始化创建对象。
例 8-19
( 2)当对象作函数参数时,因为要用实参初始化
形参,也要调用拷贝构造函数。
( 3)函数返回值为类类型时,情况也类似。
例 8-22
C++程序设计 湖南大学 杜四春、银红霞
8.7 this指针
当一个成员函数被调用时, 自动向它传递一个隐
含的参数, 该参数是一个指向这个函数成员所在的对
象的指针 。 成员函数中可以用 this关键字来引用该指针 。
this指针的类型就是成员函数所属的类的类型 。 当调用
成员函数时, 它被初始化为被调用函数所在的类实例
的地址 。
例 8-23
注意,this指针只能在类的成员函数中使用, 它指
向该成员函数被调用的对象 。 this指针一般用于返回当
前对象自身 。 this指针大量用于运算符重载成员函数设
计中 。 静态成员函数没有 this指针 。 因为类只有一个静
态成员函数实例, 所以使用 this指针没有什么意义 。 在
静态成员函数中使用 this指针会引起编译错误 。
C++程序设计 湖南大学 杜四春、银红霞
8.8 引用
8.8.1 引用标识符 &
C++中用 & 可派生出一个引用类型, 即产生同
一变量的另一个名字 。 引用在C++中非常普遍, 主
要用途是为用户定义类型指定操作, 还可用于函数参
数的传递, 对引用型参数的操作, 就是对实际参数的
操作 。 例如:
main()
{
int num=50;
int& ref=num;
ref+=10;
printf("num=%d",num);
}
此程序的运行结果为:
num=60
注意:若引用的是 const
变量,则编译器产生一个
同值的临时变量,引用的
是该临时变量。
C++程序设计 湖南大学 杜四春、银红霞
8.8.2 const和 volatile
const 和 volatile是类型修饰符 。 在变量说明语句
中, const 用于冻结一个变量, 使其在程序中不能被修
改 。 在用 const 说明变量时, 必须对该变量进行初始
化 。 用 volatile修饰的变量, 虽然在一段程序中没有明
显被改动, 单这个变量的值也会因为程序外部的原因
( 如中断等 ) 而改变 。
C++程序设计 湖南大学 杜四春、银红霞
8.9 常类型
8.9.1 常引用
如果在说明引用时用 const修饰, 则被说明的引用
为常引用 。 常引用所引用的对象不能被更新 。 如果用
常引用做形参, 便不会意外地发生对实参的更改 。 常
引用的说明形式如下:
const <类型说明符 > & <引用名 >;
例如:
const int &n;
其中, n是一个常引用, 它所引用的对象不会被更
新 。 如果出现,n=123; 则是非法的 。
常引用作形参, 在函数中不能更新它所引用的对
象, 因此对应的实参不会被破坏 。
C++程序设计 湖南大学 杜四春、银红霞
8.9.2 常对象
常对象是指对象常量, 定义格式如下:
<类名 > const <对象名 >;
或者
const <类名 > <对象名 >;
在定义常对象时必须进行初始化,而且不能被更
新。只有常成员函数才能操作常对象,没有使用 const
关键词说明的成员函数不能用来操作常对象。
C++程序设计 湖南大学 杜四春、银红霞
8.9.3 常对象成员
常对象成员包括常成员函数和常数据成员 。
1,常成员函数
使用 const关键词说明的函数为常成员函数, 常成
员函数说明格式如下:
<类型 > <函数名 >(<参数表 >) const;
C++程序设计 湖南大学 杜四春、银红霞
对于常对象成员需要注意以下几点:
( 1) const是函数类型的一个组成部分, 因此在实
现部分也要带 const关键词 。
( 2) 常成员函数不更新对象的数据成员, 也不能
调用该类中没有用 const修饰的成员函数 。
( 3) 如果将一个对象说明为常对象, 则通过该常
对象只能调用它的常成员函数, 而不能调用其他成员
函数 。
( 4) const关键词可以参与区分重载函数 。 例如,
如果在类中有说明:
void print();
void print() const;
则这是对 print的有效重载。
C++程序设计 湖南大学 杜四春、银红霞
2,常数据成员
就像一般数据一样,类的成员数据也可以是常量
和常引用,使用 const说明的数据成员为常数据成员。
如果在一个类中说明了常数据成员,那么构造函数就
只能通过初始化列表对该数据成员进行初始化。