类和对象及其封装性

101
类类类类类类类类类

Upload: graiden-frederick

Post on 01-Jan-2016

24 views

Category:

Documents


2 download

DESCRIPTION

类和对象及其封装性. 回顾:面向对象的方法. 目的: 实现软件设计的产业化。 观点: 自然界是由实体(对象)所组成。 程序设计方法: 使用面向对象的观点来描述模仿并处理现实问题。 要求: 高度概括、分类、和抽象。. 抽象. 抽象是对具体对象(问题)进行概括,抽出这一类对象的公共性质并加以描述的过程。 先注意问题的本质及描述,其次是实现过程或细节。 数据抽象:描述某类对象的属性或状态(对象相互区别的物理量)。 代码抽象:描述某类对象的共有的行为特征或具有的功能。 抽象的实现:通过类的声明。. 抽象实例——钟表. 数据抽象: - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 类和对象及其封装性

类和对象及其封装性

Page 2: 类和对象及其封装性

回顾:面向对象的方法

• 目的:– 实现软件设计的产业化。

• 观点:– 自然界是由实体(对象)所组成。

• 程序设计方法:– 使用面向对象的观点来描述模仿并处理

现实问题。• 要求:– 高度概括、分类、和抽象。

Page 3: 类和对象及其封装性

抽象抽象是对具体对象(问题)进行概括,

抽出这一类对象的公共性质并加以描述的过程。– 先注意问题的本质及描述,其次是实现过

程或细节。– 数据抽象:描述某类对象的属性或状态

(对象相互区别的物理量)。– 代码抽象:描述某类对象的共有的行为特

征或具有的功能。– 抽象的实现:通过类的声明。

Page 4: 类和对象及其封装性

抽象实例——钟表

• 数据抽象:int Hour, int Minute, int Second

• 代码抽象:SetTime(), ShowTime()

Page 5: 类和对象及其封装性

抽象实例——钟表类class Clock{ public: void SetTime(int NewH, int NewM, int NewS); void ShowTime(); private: int Hour,Minute,Second;};

Page 6: 类和对象及其封装性

抽象实例——人

•数据抽象:char *name,char *sex,int age,int id

•代码抽象:生物属性角度:GetCloth(), Eat(), Step(),…

社会属性角度:Work(), Promote() ,…

Page 7: 类和对象及其封装性

封装

将抽象出的数据成员、代码成员相结合,将它们视为一个整体。– 目的是曾强安全性和简化编程,使用者

不必了解具体的实现细节,而只需要通过外部接口,以特定的访问权限,来使用类的成员。

– 实现封装:类声明中的 {}

Page 8: 类和对象及其封装性

封装• 实例:

class Clock{ public: void SetTime(int NewH,int NewM,

int NewS); void ShowTime();

private: int Hour,Minute,Second;};

边界

特定的访问权限

外部接口

Page 9: 类和对象及其封装性

9

类与对象的声明和定义 1. 类的定义 类的定义 :– 成员函数的定义– 数据成员的定义

Page 10: 类和对象及其封装性

10

2 、声明类的一般形式为 class 类名 { private : 私有数据和函数 public : 公有数据和函数 protected : 保护数据和函数 } ;

Page 11: 类和对象及其封装性

11

3 、说明( 1 )类声明以关键字 class 开始,其后跟类名。( 2 )类所声明的内容用花括号括起来,这一对

花括号“ { }” 之间的内容称为类体。( 3 )类中定义的数据和函数分别是数据成员和

成员函数

Page 12: 类和对象及其封装性

12

4 、访问权限( 1 )用于控制对象的某个成员在程序中的

可访问性( 2 )关键字 private 、 public 和 protected 定义的

成员访问权限分别是私有、公有和保护的,把这些成员分别叫做私有成员、公有成员和保护成员

( 3 )所有成员默认声明为 private 权限。

Page 13: 类和对象及其封装性

13

例 : 定义一个 Person 类class Person {private:

char Name[20];int Age;char Sex;

public:void Register(char *name, int age, char sex);void ShowMe();

};

Page 14: 类和对象及其封装性

14

成员函数的定义返回类型 类名∷成员函数名(参数列表) { 成员函数的函数体 // 内部实现 }

其中“∷”是作用域运算符,“类名”是成员函数所属类的名字,“∷”用于表明其后的成员函数是属于这个特定的类。换言之,“类名∷成员函数名”的意思就是对属于“类名”的成员函数进行定义,而“返回类型”则是这个成员函数返回值的类型。余下的工作就是定义成员函数的函数体。

Page 15: 类和对象及其封装性

15

二、对象的定义定义格式: < 类名 > < 对象 1> , < 对象 2> ,… ;例如: Person person1,person2;

Page 16: 类和对象及其封装性

16

3 成员函数一、成员函数的定义

格式: < 类型 > < 类名 >::< 函数名 >(< 参数表 >) { < 函数体 > }

二、内联成员函数使用关键字 inline 将成员函数定义为内联函数例如: inline void Person:: Register(char *name, int age, char

sex) {…… ; }

Page 17: 类和对象及其封装性

17

例 : Person 类成员函数的定义void Person:: Register(char *name, int age, char sex){ strcpy(Name, name);

Age = age;Sex = (sex == 'm'? 'm':‘f');

}void Person:: ShowMe(){ cout << Name << '\t' << Age << '\t' << Sex << endl; }

Page 18: 类和对象及其封装性

18

4 对象的访问1 、在类的作用域内,成员函数直接访问同类

中的数据成员2 、在类的作用域外,对象访问其数据成员或

成员函数需使用运算符“.”3 、在类的作用域外,禁止直接访问一个对象

中的私有成员4 、同类对象之间可以整体赋值5 、对象用作函数的参数时属于赋值调用;函

数可以返回一个对象

Page 19: 类和对象及其封装性

19

例 : 完整的人事资料输入输出程序

int main(){

char name[20], sex;int age;Person person1, person2;cout << "Enter a person's name, age and sex:";cin >> name >> age >> sex;person1.Register(name, age, sex);

Page 20: 类和对象及其封装性

20

cout << "person1: \t";person1.ShowMe(); // 调用类的成员函数输出person1.Register("Zhang3", 19, 'm');cout << "person1: \t";person1.ShowMe(); // 调用类的成员函数输出person2 = person1; // 对象之间的赋值cout << "person2: \t";person2.ShowMe(); // 调用类的成员函数输出return 0;

}

Page 21: 类和对象及其封装性

21

例 : 简单的日期类定义一个最简单的日期类,仅包含说明日期的数据成员。// Example : 最简单的日期类#include <iostream>using namespace std;class Date{public:

int day, month, year;};

Page 22: 类和对象及其封装性

22

int main(){Date date1, date2; // 声明 2 个日期对象

cin >> date1.day >> date1.month >> date1.year;cout << date1.month << “-“ << date1.day << “-“ << date1.year << endl;cin >> date2.day >> date2.month >> date2.year;cout << date2.month << “-“ << date2.day << “-“ << date2.year << endl;return 0;

}

Page 23: 类和对象及其封装性

23

例 : 定义最简单的日期类,用函数实现对象的输入输出操作。

#include <iostream>using namespace std;class Date{ public:

int day, month, year;};void set_date(Date& d);void show_date(Date d);

Page 24: 类和对象及其封装性

24

int main(){

Date date1, date2; // 声明 2 个日期对象set_date(date1); // 使用全局函数操作数据成员show_date(date1);set_date(date2);show_date(date2);return 0;

}

Page 25: 类和对象及其封装性

25

void set_date(Date& d){

cin >> d.day >> d.month >> d.year;}void show_date(Date d){

cout << d.month << "-" << d.day << "-" << d.year << endl;

}

Page 26: 类和对象及其封装性

26

例 定义简单的完整意义上的日期类#include <iostream>using namespace std;class Date{

int day, month, year;public:

void init(int,int,int); // 初始化数据成员void print_ymd();void print_mdy();

};

Page 27: 类和对象及其封装性

27

void Date::init(int yy, int mm, int dd){ month = ( mm >= 1 && mm <= 12 ) ? mm : 1;

year = ( yy >= 1900 && yy <= 2100 ) ? yy : 1900;day = ( dd >= 1 && dd <= 31 ) ? dd : 1;

}void Date::print_ymd(){ cout << year << "-" << month << "-" << day << endl;}void Date::print_mdy(){ cout << month << "-" << day << "-" << year << endl;}

Page 28: 类和对象及其封装性

28

int main(){ Date date1,date2;

date1.print_ymd(); // 未初始化时的情况date1.init(2006,3,28); // 正确的初始化数据date1.print_ymd();date1.print_mdy();date2.init(2006,13,38); // 错误的初始化数据date2.print_ymd();date2.print_mdy();return 0;

}

Page 29: 类和对象及其封装性

29

程序设计举例• 点类和圆类• 在二维平面空间上,使用( x , y )坐标可

以确定一个点,确定了圆心坐标和半径可以确定一个圆。声明一个点类,并使用这个点类的对象为数据成员声明圆类。

Page 30: 类和对象及其封装性

30

// Point.h文件 Point 类的声明#ifndef POINT_H#define POINT_Hclass Point { int x, y; // 点的 x 和 y 坐标public:

void SetPoint( int, int ); // 设置坐标int GetX() { return x; } // 取 x 坐标int GetY() { return y; } // 取 y 坐标void Print(); // 输出点的坐标

};#endif

Page 31: 类和对象及其封装性

31

// Point.cpp文件 Point 类的成员函数定义

#include <iostream>using namespace std;#include "point.h"void Point::SetPoint( int a, int b ){ x = a;

y = b;}void Point::Print(){ cout << '[' << x << ", " << y << ']';}

Page 32: 类和对象及其封装性

32

// Circle.h文件 Circle 类的声明#ifndef CIRCLE_H#define CIRCLE_H#include <iostream>using namespace std;#include "point.h"class Circle{ double Radius;

Point Center;

Page 33: 类和对象及其封装性

33

public:void SetRadius(double); // 设置半径void SetCenter(Point); // 设置圆心坐标double GetRadius(); //取半径Point GetCenter(); //取圆心double Area(); // 计算面积void Print(); // 输出圆心坐标和半径

};#endif

Page 34: 类和对象及其封装性

34

// Circle.cpp文件 Circle 类的成员函数定义

#include <iostream>using namespace std;#include "circle.h"void Circle::SetRadius(double r){ Radius = ( r >= 0 ? r : 0 );}void Circle::SetCenter(Point p){ Center = p;}Point Circle::GetCenter(){ return Center;}

Page 35: 类和对象及其封装性

35

double Circle::GetRadius(){

return Radius;}double Circle::Area(){

return 3.14159 * Radius * Radius;}void Circle::Print(){

cout << "Center = ";Center.Print();cout << "; Radius = " << Radius << endl;

}

Page 36: 类和对象及其封装性

36

// Example.cpp文件 : Circle Demo#include <iostream>using namespace std;#include "point.h"#include "circle.h"int main(){

Point p,center;p.SetPoint(30,50);center.SetPoint(120,80);Circle c;c.SetCenter(center);c.SetRadius(10.0);

Page 37: 类和对象及其封装性

37

cout << "Point p: ";p.Print();cout << "\nCircle c: ";c.Print();cout << "The centre of circle c: ";c.GetCenter().Print();cout << "\nThe area of circle c: " << c.Area() << endl;return 0;

}

Page 38: 类和对象及其封装性

38

构造函数• 构造函数( constructor )– 用于对对象进行初始化的一个或一组函数。

• 构造函数是特殊的公有成员函数,其特征如下:1. 函数名与类名相同。2.构造函数无函数返回类型说明。3. 在新的对象被建立时,该对象所属的类的构造

函数自动被调用。4.构造函数可以重载。它们由不同的参数表区分。

Page 39: 类和对象及其封装性

39

对象的初始化和构造函数例 : 定义一个带构造函数的日期类。#include <iostream>using namespace std;class Date{ int day,month,year;public:

Date(); //构造函数void init(int,int,int); // 对数据成员赋值void print_ymd();void print_mdy();

};

Page 40: 类和对象及其封装性

40

Date::Date(){

year = 1900;month = 1;day = 1;

}

Page 41: 类和对象及其封装性

41

void Date::init(int yy, int mm, int dd){ month = ( mm >= 1 && mm <= 12 ) ? mm : 1;

year = ( yy >= 1900 && yy <= 2100 ) ? yy : 1900;day = ( dd >= 1 && dd <= 31 ) ? dd : 1;

}void Date::print_ymd(){ cout << year << "-" << month << "-" << day <<

endl;}void Date::print_mdy(){ cout << month << "-" << day << "-" << year <<

endl;}

Page 42: 类和对象及其封装性

42

int main(){

Date date1, date2; //创建 2 个日期类对象date1.print_ymd(); // 输出使用 init 赋值前对象的内容date2.print_ymd();date1.init(2006, 3, 28); // 正确的赋值数据date1.print_ymd();date1.print_mdy();date2.init(2006,13,38); // 错误的赋值数据date2.print_ymd();date2.print_mdy();return 0;

}

Page 43: 类和对象及其封装性

43

二、构造函数的重载构造函数重载时,这些构造函数的参数的个数或类型不同例 : 定义一个带重载构造函数的日期类。#include <iostream>using namespace std;class Date{ int day,month,year;public:

Date(); //构造函数Date(int,int,int); //构造函数void init(int,int,int);void print_ymd();void print_mdy();

};

Page 44: 类和对象及其封装性

44

Date::Date(){

year = 1900;month = 1;day = 1;

}Date::Date(int yy, int mm, int dd){

init(yy,mm,dd);}

Page 45: 类和对象及其封装性

45

void Date::init(int yy, int mm, int dd){ month = ( mm >= 1 && mm <= 12 ) ? mm : 1;

year = ( yy >= 1900 && yy <= 2100 ) ? yy : 1900;day = ( dd >= 1 && dd <= 31 ) ? dd : 1;

}void Date::print_ymd(){ cout << year << "-" << month << "-" << day <<

endl;}void Date::print_mdy(){ cout << month << "-" << day << "-" << year <<

endl;}

Page 46: 类和对象及其封装性

46

int main(){ // 使用 2 个不同的重载构造函数创建 2 个日期类对象

Date date1, date2(2006,3,28);date1.print_ymd();date2.print_ymd();date1.init(2006,3,28);date1.print_ymd();date2.init(2006,4,8);date2.print_ymd();return 0;

}

Page 47: 类和对象及其封装性

47

三 . 数据成员的初始化1 .在构造函数的函数体中进行初始化。2 .在构造函数的头部初始化。3 .混合初始化4. 使用默认参数初始化。

Page 48: 类和对象及其封装性

48

1. 在构造函数的函数体中初始化class Person{ char Name[20]; int Age; char Sex;public:

Person(){ strcpy(Name, "XXX");

Age = 0;Sex = 'm'; }

}例如 , 当遇到声明

Person personl;Person person2;

Page 49: 类和对象及其封装性

49

2. 在构造函数的头部初始化。其格式为:

< 类名 >::<构造函数 >(< 参数表 >) : <变量 1> ( < 初值 1> ) , …, <变量 n> ( < 初值 n> )

{……}

例如Person::Person(): Age(0),Sex('m')

{ }

Page 50: 类和对象及其封装性

50

3.混合初始化 。例如Person::Person(): Age(0),Sex('m'){strcpy(m_strName, “XXX”);}

Page 51: 类和对象及其封装性

51

例 构造函数中数据成员初始化的不同方法

#include <iostream>using namespace std;class Date{ int day, month, year;public:

Date():year(1900), month(1), day(1) //构造函数,无参数,使用参数初始化表{ }

Page 52: 类和对象及其封装性

52

Date(int yy, int mm=1, int dd=1); //构造函数,3 个参数, 2 个有默认值Date(Date& d) //拷贝构造函数{ year = d.year;

month = d.month;day = d.day;

}void print_ymd();

};

Page 53: 类和对象及其封装性

53

Date::Date(int yy, int mm, int dd):year(yy), month(mm), day(dd) { }

void Date::print_ymd(){ cout << year << "-" << month << "-" << day <<

endl;}

Page 54: 类和对象及其封装性

54

int main(){ Date date1; // 使用无参数的构造函数创建

日期类对象cout << "date1:";date1.print_ymd();Date date2(2006); // 使用 3 参数的构造函数创建日期类对象, 2 个默认值cout << "date2:";date2.print_ymd();Date date3(2006, 4); // 使用 3 参数的构造函数创建日期类对象, 1 个默认值

Page 55: 类和对象及其封装性

55

cout << "date3:";date3.print_ymd();Date date4(2006, 4, 8); // 使用 3 参数的构造函数创建日期类对象cout << "date4:";date4.print_ymd();Date date5(date4); // 使用拷贝构造函数创建日期类对象cout << "date5:";date5.print_ymd();return 0;

}

Page 56: 类和对象及其封装性

56

析构函数• 析构函数( destructor )–当一个对象的生命周期结束时, C++也会自动

调用一个函数注销该对象并进行善后工作。

Page 57: 类和对象及其封装性

57

1. 构函数名与类名相同,但在前面加上字符‘ ~’ ,如~CGoods ()。

2. 析构函数无函数返回类型。3. 一个类有一个也只有一个析构函数。4. 析构函数不带任何参数,因此不能重载

Page 58: 类和对象及其封装性

58

例 : 为类 Person增加构造函数和析构函数

#include <iostream>#include <cstring>using namespace std;class Person {

char Name[20];int Age;char Sex;

Page 59: 类和对象及其封装性

59

public:Person() //构造函数{ strcpy(Name, "XXX");

Age = 0;Sex = 'm';

}~Person() //析构函数{ cout<<"Now destroying the instance of Person"<<endl;}void Register(char *name, int age, char sex);void ShowMe();

};

Page 60: 类和对象及其封装性

60

void Person:: Register(char *name, int age, char sex){ strcpy(Name, name);

Age = age;Sex = (sex == 'm'?'m':'f');

}void Person:: ShowMe(){ cout << Name << '\t' << Age << '\t' << Sex << endl;}

Page 61: 类和对象及其封装性

61

int main(){ Person person1, person2; // 对象调用构造函数

cout << "person1: \t";person1.ShowMe();person1.Register("Zhang3", 19, 'm');cout << "person1: \t";person1.ShowMe();cout << "person2: \t";person2.ShowMe();person2 = person1; // 对象之间的赋值cout << "person2: \t";person2.ShowMe();return 0;

}

Page 62: 类和对象及其封装性

类的应用举例一圆型游泳池如图所示,现在需在其周围建一圆

型过道,并在其四周围上栅栏。栅栏价格为 35 元 /米,过道造价为 20 元 / 平方米。过道宽度为 3米,游泳池半径由键盘输入。要求编程计算并输出过道和栅栏的造价。

游泳池

过道

Page 63: 类和对象及其封装性

#include <iostream.h>

const float PI = 3.14159;const float FencePrice = 35;const float ConcretePrice = 20;

// 声明类 Circle 及其数据和方法class Circle{ private: float radius; public: Circle(float r); //构造函数 float Circumference() const; // 圆周长 float Area() const; // 圆面积};

Page 64: 类和对象及其封装性

// 类的实现// 构造函数初始化数据成员 radiusCircle::Circle(float r){radius=r}

// 计算圆的周长float Circle::Circumference() const{ return 2 * PI * radius;} // 计算圆的面积 float Circle::Area() const{ return PI * radius * radius;}

Page 65: 类和对象及其封装性

void main (){ float radius; float FenceCost, ConcreteCost; // 提示用户输入半径 cout<<"Enter the radius of the pool: "; cin>>radius;

// 声明 Circle 对象 Circle Pool(radius); Circle PoolRim(radius + 3);

Page 66: 类和对象及其封装性

// 计算栅栏造价并输出 FenceCost = PoolRim.Circumference() * FencePrice; cout << "Fencing Cost is ¥ " << FenceCost << endl; // 计算过道造价并输出 ConcreteCost = (PoolRim.Area() - Pool.Area())*ConcretePrice; cout << "Concrete Cost is ¥ " << ConcreteCost << endl;}

运行结果Enter the radius of the pool: 10Fencing Cost is ¥ 2858.85Concrete Cost is ¥ 4335.39

Page 67: 类和对象及其封装性

什么是类的组合

• 类中的成员数据是另一个类的对象。

• 可以在已有的抽象的基础上实现更复杂的

抽象。

Page 68: 类和对象及其封装性

举例class Point{ private: float x,y; // 点的坐标 public: Point(float h,float v); //构造函数 float GetX(void); // 取 X 坐标 float GetY(void); // 取 Y 坐标 void Draw(void); // 在 (x,y) 处画点};//... 函数的实现略

Page 69: 类和对象及其封装性

class Line

{

private:

Point p1,p2; //线段的两个端点 public:

Line(Point a,Point b); //构造函数 Void Draw(void); //画出线段};

//... 函数的实现略

Page 70: 类和对象及其封装性

类组合的构造函数设计

• 原则:不仅要负责对本类中的基本类型成员数据赋初值,也要对对象成员初始化。

• 声明形式:类名 :: 类名 ( 对象成员所需的形参,本类成员形参 )

:对象 1( 参数 ) ,对象 2( 参数 ) , ......

{ 本类初始化 }

Page 71: 类和对象及其封装性

类组合的构造函数调用

• 构造函数调用顺序:先调用内嵌对象的构造函数(按内嵌时的声明顺序,先声明者先构造)。然后调用本类的构造函数。(析构函数的调用顺序相反)

• 若调用缺省构造函数(即无形参的),则内嵌对象的初始化也将调用相应的缺省构造函数。

Page 72: 类和对象及其封装性

类的组合举例(二)class Part // 部件类{ public: Part(); Part(int i); ~Part(); void Print(); private: int val;};

Page 73: 类和对象及其封装性

class Whole { public: Whole(); Whole(int i,int j,int k); ~Whole(); void Print(); private: Part one; Part two; int date;};

Page 74: 类和对象及其封装性

Whole::Whole()

{

date=0;

}

Whole::Whole(int i,int j,int k):

two(i),one(j),date(k)

{}

//... 其它函数的实现略

Page 75: 类和对象及其封装性

75

对象与指针一、指向对象的指针

1 、定义格式: 类名 *指针变量名表;

例: Person person1;Person *ptr=&Person1;

ptr->ShowMe();

Page 76: 类和对象及其封装性

76

2 、动态存储–指针变量= new 名字 ( 名字初始化值 );– delete 指针变量 ;– 例 : Person *p=new Person;– p->ShowMe(); delete p;

Page 77: 类和对象及其封装性

77

例 使用动态存储实现前例程序的功能。

#include <iostream>#include <cstring>using namespace std;int main(){ Person *p1,*p2; // 声明两个指向对象的指针

p1=new Person; //动态生成一个 Person 对象cout << "person1: \t";p1->ShowMe();p1->Register("Zhang3", 19, 'm');cout << "person1: \t";p1->ShowMe();p2=new Person; //动态生成一个 Person 对象

Page 78: 类和对象及其封装性

78

cout << "person2: \t";p2->ShowMe();*p2 = *p1; // 对象之间的赋值cout << "person2: \t";p2->ShowMe();delete p1; //释放 p1指针指向对象所占的空间delete p2; //释放 p2指针指向对象所占的空间return 0;

}

Page 79: 类和对象及其封装性

79

二、指向对象成员的指针1 、指向对象数据成员的指针变量的声明与指

向普通变量的指针完全一样– 例: Date date1;– int *p;– p=&date1.year;– *p=2007;

Page 80: 类和对象及其封装性

80

2 、指向对象成员函数的指针变量声明时要指明它所属的类– (1) 定义形式– 数据类型名 ( 类名 ::*指针变量名)(参数表) – (2)指向成员函数–指针变量名 = 类名 :: 成员函数名– 例: Date date1;– void (Date::*p)(int,int,int);– p=Date::init; – (date1.*p)(2007,4,8);

Page 81: 类和对象及其封装性

81

例: 编写程序,演示对象指针的使用方法

#include <iostream>using namespace std;class Date{public:

int day, month, year;void init(int,int,int);void print_ymd();

};

Page 82: 类和对象及其封装性

82

void Date::init(int yy, int mm, int dd){ year = yy;

month = mm;day = dd;

}void Date::print_ymd(){ cout << year << "-" << month << "-" << day <<

endl;}

Page 83: 类和对象及其封装性

83

int main(){ Date date1;

Date *p1 = &date1; //指向对象的指针p1->init(2006,3,28);p1->print_ymd();int * p2;p2 = &date1.year; //指向对象数据成员的指针cout << *p2 << endl;

Page 84: 类和对象及其封装性

84

void (Date::*p3)(int,int,int); //指向对象成员函数的指针void (Date::*p4)(); //指向对象成员函数的指针p3 = Date::init;p4 = Date::print_ymd;(date1.*p3)(2006,4,8);(date1.*p4)();return 0;

}

Page 85: 类和对象及其封装性

85

三、 this指针1 、 C++ 中每一个类的成员函数都包含一个指

向本类对象的指针2 、指针名为 this3 、该指针包含了当前被调用的成员函数所在

对象的起始地址。

Page 86: 类和对象及其封装性

86

例: 编写程序,演示 this指针的使用。

// Example 使用 this指针 #include <iostream.h>class Test { int x;public:

Test( int = 0 ); void print();

};

Page 87: 类和对象及其封装性

87

Test::Test( int a ) { x = a; } // 构造函数void Test::print(){ cout << " x = " << x << "\n this->x = " << this->x << "\n(*this).x = " << ( *this ).x << endl;}int main(){ Test testObject( 12 );

testObject.print();return 0;

}

Page 88: 类和对象及其封装性

88

自学内容例: 扩充前例的功能,使其能进行简单的日期计

算。#include <iostream >#include <cmath>using namespace std;class Date{ int day, month, year;

void IncDay(); // 日期增加一天int DayCalc(); //距基准日期的天数

Page 89: 类和对象及其封装性

89

public:Date( int y = 1900, int m = 1, int d = 1 ); //构造函数void SetDate( int yy, int mm, int dd ); // 日期设置bool IsLeapYear(); // 是否闰年 ?bool IsEndofMonth(); // 是否月末 ?void print_ymd(); // 输出日期 yy_mm_ddvoid print_mdy(); // 输出日期 mm_dd_yyvoid AddDay(int); // 日期增加任意天int Daysof2Date(Date ymd); //两个日期之间的天数

};

Page 90: 类和对象及其封装性

90

Date::Date(int y,int m,int d){

SetDate(y,m,d);}

Page 91: 类和对象及其封装性

91

void Date::SetDate( int yy, int mm, int dd ){ month = ( mm >= 1 && mm <= 12 ) ? mm : 1; //月份的有效性判断

year = ( yy >= 1900 && yy <= 2100 ) ? yy : 1900; //年份的有效性判断switch(month){ //小月的天数判断case 4:case 6:case 9:case 11:

day = ( dd >= 1 && dd <= 30 ) ? dd : 1; break;case 2: //2月的天数判断

if (IsLeapYear())day = ( dd >= 1 && dd <= 29 ) ? dd : 1;

else day = ( dd >= 1 && dd <= 28 ) ? dd : 1;break;

default: //大月的天数判断day = ( dd >= 1 && dd <= 31 ) ? dd : 1;

}}

Page 92: 类和对象及其封装性

92

void Date::AddDay( int days ){

for ( int i = 0; i < days; i++ )IncDay();

}

Page 93: 类和对象及其封装性

93

bool Date::IsLeapYear(){ if ( year % 400 == 0 || ( year % 100 != 0 &&

year % 4 == 0 ) )return true; // 闰年

elsereturn false; // 不是闰年

}

Page 94: 类和对象及其封装性

94

bool Date::IsEndofMonth(){ switch(month) { //每月的最后一天为月末

case 4:case 6:case 9:case 11: return day == 30; case 2:

if (IsLeapYear())return day == 29;

else return day == 28;default: return day == 31; }

}

Page 95: 类和对象及其封装性

95

void Date::IncDay(){ if ( IsEndofMonth())

if (month == 12){ // 年末day = 1;month = 1;year++;}

else { // 月末day = 1;month++;}

else day++;}

Page 96: 类和对象及其封装性

96

void Date::print_ymd(){cout << year << "-" << month << "-" << day << endl;}void Date::print_mdy(){ char *monthName[ 12 ] = {"January","February", "March",

"April", "May", "June","July", "August", "September", "October","November",

"December" };cout << monthName[ month-1 ] << ' '<< day << ", " << year << endl;

}

Page 97: 类和对象及其封装性

97

int Date::DayCalc(){ int days;

int yy = year - 1900;days = yy*365; // 不计闰年的天数if(yy) days += (yy-1)/4; //每逢闰年增加一天switch(month){ //当前日期已过去月份的天数case 12:days = days + 30;case 11:days = days + 31;

Page 98: 类和对象及其封装性

98

case 10:days = days + 30;case 9:days = days + 31;case 8:days = days + 31;case 7:days = days + 30;case 6:days = days + 31;case 5:days = days + 30;case 4:days = days + 31;

Page 99: 类和对象及其封装性

99

case 3:if(IsLeapYear())days = days + 29;

else days = days + 28;case 2:days = days + 31;default:break;}days = days + day;return days;

}

Page 100: 类和对象及其封装性

100

int Date::Daysof2Date(Date ymd){ int days;

days = abs(DayCalc()-ymd.DayCalc());return days;

}

Page 101: 类和对象及其封装性

101

int main(){ Date date1,date2;

date1.print_ymd();date1.print_mdy();date1.SetDate(2006,4,8);cout << "the current date is: ";date1.print_ymd();date1.AddDay(365);cout << "After 365 days, the date is: ";date1.print_ymd();cout << "And after " << date1.Daysof2Date(Date(2008,8,8))

<< " days, the Beijing Olympic Games will open." <<endl;return 0;

}