Top Banner
1/63 程程程程程程程程程程程 程程程程程 程程程程程程 程程程 程程程程
63

程序设计基础

Jan 04, 2016

Download

Documents

nathalie-dumont

程序设计是计算机学科的. 核心和灵魂. 程序设计基础. 第五章 类与对象. 类的作用 类界面与类实现 类成员的访问控制 对象的创建 静态数据成员 构造函数与析构函数 成员对象的初始化. §5.1 类的引入. 实体:从属性与行为两个方面刻画一个实体 现实世界实体例:银行账户、学生、传感器、 … 思维世界实体例:复数、矩阵、堆栈、 … 类:描述实体的抽象概念 对象:对应于一个个具体实体. §5.1 类的引入. 5.1.1 循环计数器 循环计数: 0 0 ~359 0 、 1~12 - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 程序设计基础

1/63

程序设计是计算机学科的核心和灵魂

程序设计基础第五章 类与对象

Page 2: 程序设计基础

2/63

类的作用 类界面与类实现 类成员的访问控制 对象的创建 静态数据成员 构造函数与析构函数 成员对象的初始化

Page 3: 程序设计基础

3/63

§5.1 类的引入

实体:从属性与行为两个方面刻画一个实体 现实世界实体例:银行账户、学生、传感器、

… 思维世界实体例:复数、矩阵、堆栈、…

类:描述实体的抽象概念对象:对应于一个个具体实体

Page 4: 程序设计基础

4/63

§5.1 类的引入

5.1.1 循环计数器 循环计数: 00~3590 、 1~12

数据定义: min_val 、 max_val 、 current

函数设计: increment() 、 decrement() 、 set_mode() 、 get_value() 、 set_value

Page 5: 程序设计基础

5/63

§5.1 类的引入

5.1.1 循环计数器 保护内部数据: static int min_val; static int max_val; static int current;信息隐藏

将一个模块的内部数据或操作隐藏起来,其他模块只能通过该模块提供的公开操作来访问该模块

信息隐藏由封装机制来实现。

在 C 语言中用文件作为模块来实现

Page 6: 程序设计基础

6/63

§5.1 类的引入

5.1.1 循环计数器用文件作为模块来实现封装 CIRNUM1.Hpp // 循环计数器头文件 CIRNUM1.CPP // 实现循环计数器

Page 7: 程序设计基础

7/63

§5.1 类的引入

5.1.2 循环计数器的讨论用文件作为循环计数器模块的好处:

头文件作为模块界面,保护内部数据;应用程序不关心模块内部实现细节;便于模块设计者修改实现方法和扩展新功能。

不足:不够抽象,如定义三个记录角度、月份和时间的计数器;函数名冲突问题;模块修改必须重新编译。

增加程序可靠性和可重用

Page 8: 程序设计基础

8/63

§5.1 类的引入

5.1.3 类作为构造程序的基本单位类( class ):构造程序的基本单位,将数据以

及这些数据上的操作(函数)封装在一起。类成员( member ):数据与函数C++ 类的作用: 数据封装 类型定义

Page 9: 程序设计基础

9/63

§5.2 类的定义

5.2.1 类声明 类是对一群具有相同属性、表现相同行为的对象的

描述,类声明的一般形式 :class 类名 {

public:公有数据和函数

private:私有数据和函数

}; 类中定义的数据 ( 变量 ) 称为数据成员

类中定义的函数 ( 行为操作 ) 称为成员函数

Page 10: 程序设计基础

10/63

§5.2 类的定义5.2.1 类声明例:循环计数器类 class CIRCULAR_NUMBERS {public:

void set_mode(int min, int max){// 设置循环计数器的上、下限

min_val = min;max_val = max;return;

}void set_value(int value){// 设置循环计数器的当前值

current = value;return;

}int get_value(){// 查询循环计数器的当前值

return current;}

void increment(){// 循环计数器加一 int mode = max_val –

min_val + 1; current = ((current –

min_val) + 1) % mode + min_val;

return;}void decrement(){// 循环计数器减一 int mode = max_val –

min_val + 1; current = ((current –

min_val) - 1 + mode) % mode + min_val;

return;}private:

int min_val;// 最小值int max_val;// 最大值int current;// 当前值

};

Page 11: 程序设计基础

11/63

§5.2 类的定义

5.2.1 类声明说明: 类的数据成员允许是任何数据类型,但不能是本类类型的。

正在定义的类名只可以以指针形式声明自己类中的数据成员class Link { class Link {

Link member; Link *member;

…… ……

}; };

Page 12: 程序设计基础

12/63

§5.2 类的定义

5.2.1 类声明 类中的数据成员不允许使用初值表达式class CIRCULAR_NUMBERS {

…private:

int min_val ;int max_val ;…

}; 类中的数据成员不允许使用 auto,register,extern

修饰,但允许使用 static 修饰,得到静态数据成员:供该类的所有对象公用

= 0

= 359

Page 13: 程序设计基础

13/63

§5.2 类的定义5.2.1 类声明 在类中 const 的使用I. const 修饰数据成员:用于声明类中的一个常量数据成员。由于类的数

据成员在声明时不能有初值表达式,因此类的常量数据成员在声明时不能指定常量值。class C { const double PI ;

……};

II. const 修饰成员函数:常量成员函数,常量成员函数中不允许修改本类数据成员的值。class C {

int get_value() const { …… }

};

Page 14: 程序设计基础

14/63

§5.2 类的定义

5.2.2 类成员的访问控制 指明成员的可访问性 私有段:由 private 标记的段

段内的数据成员和成员函数称为私有成员,仅能由该类中的成员函数来访问,即仅可在成员函数定义中使用私有成员的名字。

公有段:由 public 标记的段段内的数据成员和成员函数称为公有成员,

为该类提供与外部世界的接口界面,即可在类内也可在类外访问。

类中每一个成员都有访问控制属性,若没有明确指明,成员的访问控制方式缺省为 private 。

Page 15: 程序设计基础

15/63

§5.2 类的定义5.2.3 类界面与类实现 类的成员函数可以在类内定义,也可以在类外定义。 类界面:头文件 *.hpp

声明类,包括类的所有数据成员,以及成员函数的原型 // 程序: CIRNUM3.hpp // 功能:循环计数器头文件 class CIRCULAR_NUMBERS { public: void set_mode(int min, int max) ; // 设置循环计数器的上、下限 void set_value(int value) // 设置循环计数器的当前值 int get_value() // 查询循环计数器的当前值 void increment() // 循环计数器加 1 void decrement() // 循环计数器减 1 private:

int min_val; // 最小值int max_val; // 最大值int current; // 当前值

};

Page 16: 程序设计基础

16/63

§5.2 类的定义5.2.3 类界面与类实现 类实现:源程序 *.cpp

首先要包含类界面: #include “*.hpp”然后定义成员函数,由于此时成员函数的定义是位于类的外面,因此必须用类名和作用域运算符 :: 来修饰函数名。一般形式为:

成员函数类型 类名 :: 成员函数名 ( 形参表 ){ 函数体}

例: // 循环计数器加一void CIRCULAR_NUMBERS::increment(){ int mode = max_val - min_val + 1;

  current = ((current - min_val) + 1) % mode + min_val; return;

}

Page 17: 程序设计基础

17/63

§5.2 类的定义5.2.4 标识符的类作用域 { } 内即为类作用域 在类作用域中声明的标识符只在该类中具有可见

性 成员名限定:类中一个成员名字可以使用类名和

作用域运算符来显式指定class C { void C::set(int val)

public: { value = val;void set(int val); return;

private: }int value;

};

C::value

Page 18: 程序设计基础

18/63

§5.3 对象的创建5.3.1 对象声明 类:数据类型 具有类类型的变量称为对象,对象称为类的实例。 对象声明一般格式: < 类名 > < 对象名 >int main(){ CIRCULAR_NUMBERS angle; // 角度循环计数器

CIRCULAR_NUMBERS month; // 月份循环计数器angle.set_mode(0, 359); // 设置角度取值范围从 0 到 359angle.set_value(250); // 设置当前角度为 250month.set_mode(1, 12); // 设置月份取值范围从 1 到 12month.set_value(11); // 设置当前月为 11 月

}

小写字母

Page 19: 程序设计基础

19/63

§5.3 对象的创建

5.3.1 对象声明CIRCULAR_NUMBERS angle,month;

类 CIRCULAR_NUMBERS 的实例

set_mode()代码

increment()代码 decrement()代码

set_value()代码get_value()代码

对象 angle 0 min_val

359 max_val 250 current

set_mode() set_value()get_value() incremen

t()decrement()

类CIRCULAR_NUMBER 对象mont

h1 min_val 12 max_val 11 current

set_mode() set_value()get_value() increment()decrement()

Page 20: 程序设计基础

20/63

§5.3 对象的创建5.3.1 对象声明静态数据成员 用 static 修饰的数据成员:被分配占用一个固定的存储空间,

由此类的所有对象共享,对于类来说:静态数据成员相当于类的全局变量。

使用方法:1) 在类的界面中(定义)声明一个静态数据成员2) 在类实现中,必须再次声明并初始化这个静态数据变量

// test1.hpp // test1.cpp class C { #include “test1.hpp” private: int x; int C::s = 18 ; int y; static int s; int C::set(int i, int j) public: { x = i ; int set(int,int); y = j ; }; s++; }

Page 21: 程序设计基础

21/63

§5.3 对象的创建

5.3.1 对象声明静态数据成员 // test.cpp #include “test1.hpp”

void main( ){ C c1, c2;

c1.set(100,200);c2.set(15, 30);

}

s: 18 set ()代码

类 C

对象 c1 x

y set()

对象 c2 x y set()

100200

191530

20

Page 22: 程序设计基础

22/63

§5.3 对象的创建

5.3.2 使用对象成员 通过成员选择运算符 . 来访问 / 使用对象的公有成员 对象名 . 成员名 angle.get_value();

angle.setmode(0,359);

Page 23: 程序设计基础

23/63

§5.3 对象的创建

5.3.3 对象的生存期 对象生存期:对象从被创建开始到被释放为止的时间。 数据成员生存期有对象生存期决定,成员函数具有全局生存期( 1 )局部对象:定义在函数体内或程序块内,作用域限定在

函数体或程序块中。( 2 )静态对象:定义在一个文件中,作用域从定义时起到文

件结束。( 3 )全局对象:定义在某个文件中,作用域在包含该文件的

整个程序中。

Page 24: 程序设计基础

24/63

§5.4 对象的初始化5.4.1 构造函数 类中的一个特殊函数 功能:对该类的对象进行初始化 一般形式:类名 ( 形式参数表 ); 特点:

构造函数是公有的,可由用户提供,也可由系统提供缺省的。

构造函数可以有任何类型的形参,但是无返回值,也不能指定返回类型。

构造函数在声明一个新对象时调用(对象声明语句中为构造函数提供实参),不可显式调用

Page 25: 程序设计基础

25/63

§5.4 对象的初始化5.4.1 构造函数程序 5.4.1

// 程序: CIRNUM4.hpp // 功能:循环计数器类头文件,使用构造函数

class CIRCULAR_NUMBERS { public: CIRCULAR_NUMBERS(int min, int max, int value); // 设置循环计数器的上下限和当前值 int get_value() ; // 查询循环计数器的当前值 void increment() ; // 循环计数器加 1 void decrement() ; // 循环计数器减 1 private:

int min_val; // 最小值 int max_val; // 最大值 int current; // 当前值

};

Page 26: 程序设计基础

26/63

§5.4 对象的初始化5.4.1 构造函数程序 5.4.2 ……// 设置循环计数器的上下限和当前值CIRCULAR_NUMBERS::CIRCULAR_NUMBERS(int min, int max, int value){

min_val = (min <= max) ? min : max;max_val = (min <= max) ? max : min;if (value < min_val) current = min_val;else {

if (value > max_val) current = max_val;else current = value;

}return;

} ……

Page 27: 程序设计基础

27/63

§5.4 对象的初始化5.4.1 构造函数程序 5.4.3 ……int main(){

// 创建两个循环计数器对象并初始化CIRCULAR_NUMBERS angle(0, 359, 250); // 角 度 循环计数器CIRCULAR_NUMBERS month(1, 12, 11); // 月份循环计数器

 ……}

Page 28: 程序设计基础

28/63

§5.4 对象的初始化5.4.1 构造函数程序 5.4.4 // 程序: CIRDEMO5.cpp // 功能:演示全局对象与静态对象的初始化

#include “cirnum4.hpp” #include <iostream.h>

CIRCULAR_NUMBERS angle(0, 359, 250); // 角度循环计数器作为全局对象

int main(){

static CIRCULAR_NUMBERS month(1, 12, 11); // 月份循环计数器作为静态对象 // 显示对象状态 cout<<“The initial angle is ”<<angle.get_value()<<“\n”;  cout<<“The initial month is ”<<month.get_value()<<“\n”;}

全局对象与静态对象的构造函数在main() 函数执行之前被调用

Page 29: 程序设计基础

29/63

§5.4 对象的初始化5.4.1 构造函数程序 5.4.5 // 程序:一个时间类 DATE 的例子 // 功能:演示多个不同的构造函数

class Date { protected: int year; int month; int day; public: Date() // 构造函数,不带参数 { year=0; month=1; day=1; } Date(int y, int m, int d) // 构造函数,带参数 { year=y; month=m; day=d; } Date(Date& obj) // 构造函数,以一个同类对象为参数 { year=obj.year; month=obj.month; day=obj.day; } void print() { cout<<year<<“/”<<month<<“/”<<day<<endl; } }

Page 30: 程序设计基础

30/63

§5.4 对象的初始化5.4.2 析构函数 类中的一个特殊函数 功能:为撤销一个类的对象做善后清理工作(如:

回收存储空间) 一般形式: ~ 类名 ( ); 特点:

析构函数是公有的,可由用户提供,也可由系统提供缺省的。

析构函数不可带任何参数,无返回值,也不能指定返回类型。

在对象生存期结束时,程序将自动调用该对象所属类的析构函数,调用且仅调用一次。

Page 31: 程序设计基础

31/63

§5.4 对象的初始化5.4.2 析构函数程序 5.4.6 // 程序: DESTROY.CPP // 功能:演示构造函数与析构函数的调用

#include <iostream.h> class DEMO_CLASS {public:

DEMO_CLASS(int i);~DEMO_CLASS();

}; 

DEMO_CLASS::DEMO_CLASS(int i){ cout << "Initial value is " << i << "\n";

return;} 

DEMO_CLASS::~DEMO_CLASS(){ cout << "Goodbye!\n";

return;} 

Page 32: 程序设计基础

32/63

§5.4 对象的初始化5.4.2 析构函数int main()

{ DEMO_CLASS obj(30);// 声明一个对象cout << "This is the end of main().\n";

return 0;

}

运行结果:Initial value is 30

This is the end of main().

Goodbye!

Page 33: 程序设计基础

33/63

§5.4 对象的初始化5.4.3 对象成员的初始化 对象成员:在一个类中声明具有类类型的数据成员 初始化对象成员的方法:在本类的构造函数中调用这些对

象成员所属类的构造函数,其一般形式: 类名 :: 类名 ( 形参表 ): 初始化列表 { …… }

class A { ……public: B::B():obj2(10,20), obj1(5,3)

A(int a, float b); { ……}; }

class B {A obj1, obj2;

public:B();

}

Page 34: 程序设计基础

34/63

§5.4 对象的初始化5.4.3 对象成员的初始化

说明 如果有多个对象成员,对象成员构造函数的调用次序取决

于这些成员在类中声明的次序。 执行次序:

创建类的对象时,调用此类的构造函数,先根据初始化列表调用对象成员的构造函数,初始化对象成员,然后才执行本身的构造函数的函数体。 析构函数调用的次序相反。

Page 35: 程序设计基础

35/63

§5.4 对象的初始化5.4.3 对象成员的初始化 程序 5.4.8 // 程序: OBJECT.CPP // 功能:演示类中包含有另一个类的对象初始化 // 在构造函数和析构函数中加入输出以便跟踪

#include<iostream.h>class Object{ int val; public:

Object( ); // 构造函数Object( int i ); // 构造函数~Object( ); // 析构函数

};

Object::Object( ){ val=0; cout<<"\n Default constructor for Object.\n";}

Page 36: 程序设计基础

36/63

§5.4 对象的初始化5.4.3 对象成员的初始化 Object::Object( int i) // 构造函数定义

{ val=i; cout<<"\n Constructor for Object: "<<val<<endl;}Object::~Object( ) // 析构函数定义{ cout<<"\n Destructor for Object: "<<val<<endl;}

class Container // 定义新类,它含 Object 的对象{ private:

int date;Object one; // 对象成员Object two; // 对象成员

public:Container( ); // 构造函数Container( int i, int j, int k); // 构造函数~Container( ); // 析构函数

};

Page 37: 程序设计基础

37/63

§5.4 对象的初始化5.4.3 对象成员的初始化 Container::Container( )// 构造函数定义

{ date=0; cout<<"\n Default constructor for Container.\n";}Container::Container( int i, int j, int k):two(i),one(j){ date=k; cout<<"\n Constructor for Container.\n"; }Container::~Container( ){ cout<<"\n Destructor for Container.\n"; }

void main( ) // 演示程序{ cout<<"\n... Entering main ...\n"; Container obj(5,6,10); cout<<"\n... Exiting main ...\n";}

Page 38: 程序设计基础

38/63

§5.4 对象的初始化5.4.3 对象成员的初始化 执行结果为:

... Entering main ...

Constructor for Object: 6 // 对象 one 调用构造函数Constructor for Object: 5 // 对象 two 调用构造函数Constructor for Container. // 调用 Container 的构造函数...Exiting main ...

Destructor for Container. // 调用 Container 的析构函数Destructor for Object: 5 // 调用 two 的析构函数Destructor for Object: 6 // 调用 one 的析构函数

Page 39: 程序设计基础

39/63

§5.4 对象的初始化5.4.3 对象成员的初始化 初始化列表的其他用途 基本数据类型的数据成员也可用初始化列表做初始化class C {

public:

C(int i):number(i) C(int i)

{……} <=> { number = i;

private: ……

int number; }

};

Page 40: 程序设计基础

40/63

§5.4 对象的初始化5.4.3 对象成员的初始化 初始化列表的其他用途 常量数据成员的初始化常量数据成员:不能在类的声明中初始化(类中不能用初值表达式)不能在构造函数中设置其值(赋值操作不能用于常量)只能采用初始化列表中来赋值例: class C { C::C(int i): PI(3.14159)

public: {

C(int i); ……

private: }

const double PI ;

};

Page 41: 程序设计基础

41/63

§5.4 对象的初始化5.4.3 对象成员的初始化 // 程序: OBJECT1.CPP// 功能:演示类中包含有另一个类的对象初始化#include <iostream.h>#include <conio.h>class base{

public:base(char *s){ cout<<"Construct for Base "<<s<<"\n"; }~base() { cout<<"Destruct for Base\n"; }

};

class screen {private:

const unsigned size;long price;base obj;

public:screen(int s, long p):size(s),price(p),obj("testing"){cout<<"Construct for Screen\n"; }

void list();~screen(){ cout<<"Destruct for Screen\n"; }

};

Page 42: 程序设计基础

42/63

§5.4 对象的初始化5.4.3 对象成员的初始化 void main(){ screen nec(14,40000L);

nec.list();getch();

}

void screen::list(){ cout<<"The size of the screen is :"<<size<<"\n";

cout<<"The price of the screen is :"<<price<<"\n";}

运行结果:

Construct for Base testingConstruct for ScreenThe size of the screen is :14The price of the screen is :40000Destruct for ScreenDestruct for Base

Page 43: 程序设计基础

43/63

§5.5 使用类与对象构造程序的实例5.5.1 模拟数字式时钟 // 程序: CLOCK.HPP// 功能:时钟类的头文件

#include "cirnum4.hpp"#include <iostream.h>

class Clock {public:

Clock(int hh, int mm, int ss);void update();void show();

private:CIRCULAR_NUMBERS hour;CIRCULAR_NUMBERS minute;CIRCULAR_NUMBERS second;

};

Page 44: 程序设计基础

44/63

§5.5 使用类与对象构造程序的实例5.5.1 模拟数字式时钟 // 设置时钟当前值Clock::Clock(int hh, int mm, int ss): hour(0,23,hh), minute(0,59,mm), second(0,59,ss){

return;}

void Clock::update() // 刷新时间{

second.increment();if(second.get_value()==0) {

minute.increment();if(minute.get_value()==0)hour.increment();

}return;

}

void Clock::show() // 显示时间{

cout<<hour.get_value()<<":"<<minute.get_value()<<":"<<second.get_value()<<endl;return;

}

Page 45: 程序设计基础

45/63

§5.5 使用类与对象构造程序的实例5.5.1 模拟数字式时钟 //程序: TIMEDEMO.cpp//功能:使用类 Clock模拟数字式时钟

#include "clock.hpp"#include <iostream.h>int main(){

int loop;Clock rolex(4,15,30);Clock cima(14,0,0);cout<<"Rolex: \n"; //显示 rolex对象for(loop=1; loop<=100; loop=loop+1) {

rolex.update();rolex.show();

}cout<<"Cima: \n"; //显示 Cima对象for(loop=1; loop<=100; loop=loop+1) {

cima.update();cima.show();

}return 0;

}

Page 46: 程序设计基础

46/63

§5.5 使用类与对象构造程序的实例5.5.2 模拟加油站油泵的对象工作

//程序: PUMP.CPP//功能:加油站油泵实现文件

#include <iostream.h>#include <iomanip.h>

const float AMTINT=300.0; // 初始化油桶中的油量const float PRICE=1.25; // 单价

class Pump{protected:

float amtint,price;public:

Pump(float,float);void values();void request(float);

};

Page 47: 程序设计基础

47/63

§5.5 使用类与对象构造程序的实例5.5.2 模拟加油站油泵的对象工作

Pump::Pump(float start, float todays){ amtint=start; price=todays; }

void Pump::values(){ cout<<"The gas tank has: "<<amtint<<endl;

cout<<"The price per kg of gas is: "<<price<<endl;}

void Pump::request(float pumpamt){

float pumped;if(amtint>=pumpamt) pumped=pumpamt; //满足else pumped=amtint;amtint=amtint-pumped; // 加油后剩余数cout<<pumpamt<<" kg were requested"<<endl;cout<<pumped<<" kg were pumped"<<endl;cout<<amtint<<" kg remain in the tank"<<endl;cout<<" The total price is: "<<(pumped*price)<<endl;

}

Page 48: 程序设计基础

48/63

§5.5 使用类与对象构造程序的实例5.5.2 模拟加油站油泵的对象工作 void main(){

Pump obj(AMTINT,PRICE);obj.values();cout<<endl;obj.request(30.0);cout<<endl;obj.request(280.0);

}

程序运行结果:The gas tank has: 300The price per kg of gas is: 1.

25

30 kg were requested30 kg were pumped270 kg remain in the tankThe total price is: 37.5

280 kg were requested270 kg were pumped0 kg remain in the tankThe total price is: 337.5

Page 49: 程序设计基础

49/63

§5.5 使用类与对象构造程序的实例5.5.3 单实例对象 // 程序: SINGLE.HPP// 功能:单实例类的头文件

class Single_Instance {public:

Single_Instance();~Single_Instance();

private:static int instance_count; // 当前对象实例计数

};

#include <iostream.h>

int Single_Instance::instance_count=0; // 初始化实例计数,注意静态成员的这种用法

Single_Instance::Single_Instance() // 构造函数中必须为实例计数加 1{ instance_count++;

if(instance_count>1) cout<<"Warning: more than one object instance!"<<endl;}

Single_Instance::~Single_Instance() // 析构函数必须为实例计数减 1{ instance_count--; }

Page 50: 程序设计基础

50/63

§5.5 使用类与对象构造程序的实例5.5.3 单实例对象 // 程序: SGL_DEMO.HPP// 功能:演示单实例对象的用法

#include "single.hpp"#include <iostream.h>

int main(){

cout<<" I have the first object."<<endl;Single_Instance obj1;

cout<<" I have the second object."<<endl;Single_Instance obj2;cout<<" End of demostration"<<endl;return 0;

}

程序运行结果: I have the first object. I have the second object.Warning: more than one object instance! End of demostration

Page 51: 程序设计基础

51/63

§5.6 指向对象的指针 5.6.1 对象指针 若声明的一个指针的基类型是一个类类型,那么这个指针称

为对象指针,它指向一个类对象。如 CIRCULAR_NUMBERS* angle_ptr;

CIRCULAR_NUMBERS angle(0, 359, 250);

angle_ptr = & angle ;

通过对象指针来访问对象的成员时,必须使用成员指针运算符 -> angle_ptr->increment(); angle.increment();

Page 52: 程序设计基础

52/63

5.6.1 对象指针this 指针 C++ 为每个对象提供一个指针 this ,记录该对象的

地址,当通过对象来调用类的成员函数时, this 作为一个隐式参数传递给成员函数

this 的性质 隐式指针,不能显式声明 常指针,不能被修改,当一个类对象被创建时,

this 就被初始化为指向该对象的指针 this 是一个局部变量,局部于某个对象,在该类

的任何非静态成员函数中可见。

§5.6 指向对象的指针

Page 53: 程序设计基础

53/63

例 2 : int C::get_value( ){ return value; return this->value;}

set_mode()代码

increment()代码 decrement()代码

set_value()代码get_value()代码

对象 angle 0 min_val

359 max_val 250 current

set_mode() set_value()get_value() incremen

t()decrement()

类CIRCULAR_NUMBER 对象mont

h1 min_val 12 max_val 11 current

set_mode() set_value()get_value() increment()decrement()

5.6.1 对象指针例 1 : CIRCULAR_NUMBERS angle(0,359,250); // 角度循环计数器

CIRCULAR_NUMBERS month(1,12,11);angle.set_value(100);

100

this this

this

§5.6 指向对象的指针

Page 54: 程序设计基础

54/63

5.6.2 对象的动态创建与撤销 运算符 new 提供了动态存储分配的功能

一般形式: 指针名 = new 基类型名 ( 初始化表 );

若基类型是类类型,则 () 内为该类的构造函数提供实参。

功能:动态分配一块内存,其大小由基类型决定,若分配成功,则返回该内存的首地址给指针,否则返回 NULL

§5.6 指向对象的指针

Page 55: 程序设计基础

55/63

5.6.2 对象的动态创建与撤销例 1 : int *p ;

p = new int;*p = 10;cout << *p;

例 2 :动态分配数组int *p1;int len;cin>>len;p1 = new int[len];

p 10

p 10

§5.6 指向对象的指针

Page 56: 程序设计基础

56/63

5.6.2 对象的动态创建与撤销

例 3 :分配类对象CIRCULAR_NUMBERS* angle_ptr;

…angle_ptr = new CIRCULAR_NUMBERS(0, 359, 25

0); if(angle_ptr==NULL) { // 内存分配失败后的处理 … } else { // 内存分配成功后的处理 … } …

§5.6 指向对象的指针

分配空间失败,返回 NULL

Page 57: 程序设计基础

57/63

5.6.2 对象的动态创建与撤销 运算符 delete 用于释放用 new 分配的存储空间一般形式:

delete 指针名 ;

例: delete p;

delete []p1; // 数组释放时,加 [] 则会释放整个分配的区域,否则只会释放一个基类型占用的空间;

delete angel_ptr;

用 new 分配的内存空间,一定要用 delete 释放,而且只能释放一次。否则将产生“内存垃圾”

§5.6 指向对象的指针

Page 58: 程序设计基础

58/63

5.6.3 对象的复制与比较对象的复制与比较是针对对象的数据成员而言的。

Class Student { public: Student(const char *str) { strcpy(name,str); … } ~Student() { … } private: char name[30]; // name 以数组形式出现}

Student s1, s2;…s1=s2; // C++ 语言提供的缺省情况, s2 数据成员逐位复制给 s1

§5.6 指向对象的指针

Page 59: 程序设计基础

59/63

5.6.3 对象的复制与比较Class Student { public: Student(const char *str) { name=new char[strlen(str)+1]; strcpy(name,str); … } ~Student() { delete name; … } private: char *name; // name 以指针形式出现}

Student s1, s2;…s1=s2; // s2 中 name 指针的值复制给 s1 中的 name

设计一个专门的复制函数 Sudent *copy(Student *obj1, Student *obj2);

§5.6 指向对象的指针

对象 s1

Name

Li4\0

对象 s2

Name

zhang3\0

Page 60: 程序设计基础

60/63

§5.7 关于类与对象的进一步讨论5.7.1 基本数据类型与对象 从本质上,基本数据类型声明的变量与对象是相同的,

可以将这些变量也理解成为对象。

Clock cima(14,0,0); // 创建 Clock 对象并初始化 int i=5; <=> int i(5); // 创建 int 对象并初始化5.7.2 抽象数据类型面向对象程序设计的主要任务就是设计类并利用类组

装程序。

类与对象: 类是面向对象程序静态文本中的概念。 对象是面向对象程序动态运行时的概念。

Page 61: 程序设计基础

61/63

§5.6 关于类与对象的进一步讨论5.7.2 抽象数据类型类与抽象数据类型( Abstract Data Type—ADT ):

ADT 是类之上的一个抽象描述。 类是 ADT 的具体实现

ADT 通过定义数据结构上允许的操作的性质来定义一种数据类型,其“抽象”表现在 : 不给出数据的具体表示而只给出值域 不给出操作的实现细节而只给出其性质

类作为 ADT 的实现,其含义有: 给出了具体的数据结构表示 用面向对象程序设计语言给出了完成操作的语句序列

对象 类 抽象数据类型抽象 抽象

具体具体

Page 62: 程序设计基础

62/63

§5.7 关于类与对象的进一步讨论5.7.3 设计良好的类界面 设计类界面应考虑:

类界面具有完备性:提供的服务完整、全面。 类界面无二义性:提供的服务无二义、简单易理解。 类界面无冗余:提供的服务避免重复。

5.7.4 再论对象 对象是实体在计算机中的模拟:实体中的信息处理与实体

之间的信息传递 对象是属性与行为的封装单位: C++ 中对象的通信是通过

调用其他对象的成员函数来实现。 对象作为具有输入 / 输出的有限自动机:以其他对象的输出

作为自己的输入,自己的输入作为其他对象的输入,通信自动机。

Page 63: 程序设计基础

63/63

习题

P.176~180

5-4 , 5-5 , 5-9