第六章 类和对象 ( 二 )

79
第第第 第第第第 第第第 第第第第 ( ( ) ) § § 6.1 6.1 第第第第第第第第第 第第第第第第第第第 § § 6.2 6.2 第第 § § 6.3 6.3 第第第 § § 6.4 6.4 第第第第第第第 § § 6.5 6.5 第第第第

Upload: zona

Post on 17-Mar-2016

217 views

Category:

Documents


4 download

DESCRIPTION

第六章 类和对象 ( 二 ). § 6.1 对象指针和对象引用 § 6.2 数组 § 6.3 常类型 § 6.4 子对象和堆对象 § 6.5 类型转换. § 6.1 对象指针和对象引用. 一、指向类成员的指针. 二、对象指针和对象引用作函数参数. 三、 this 指针. < 对象 > . * < 指针名 >. < 指向对象的指针 > - > * < 指针名 >. 一、指向类成员的指针. 1. 指向 数据成员 的指针. 定义 < 类型说明符 > * < 指针名 > 赋值 < 指针名 > = & < 数据成员名 >. < 类名 > ::. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第六章 类和对象 ( 二 )

第六章 类和对象第六章 类和对象 (( 二二 ))

§§6.16.1 对象指针和对象引用对象指针和对象引用§§6.26.2 数组§§6.36.3 常类型§§6.46.4 子对象和堆对象§§6.56.5 类型转换

Page 2: 第六章 类和对象 ( 二 )

§§6.1 6.1 对象指针和对象引对象指针和对象引用用一、指向类成员的指针二、对象指针和对象引用作函数参数三、 this 指针

Page 3: 第六章 类和对象 ( 二 )

一、指向类成员的指针一、指向类成员的指针

1) 定义 < 类型说明符 > *< 指针名 >2) 赋值 < 指针名 > = & < 数据成员名 >

< 对象 >.*< 指针名 >< 指向对象的指针 > ->*< 指针名 >

1. 指向数据成员的指针

通过“对象”来引用指针“指向的成员” 成员指针运算符

< 类名 >::

3) 使用< 类名 >::

Page 4: 第六章 类和对象 ( 二 )

1) 定义 < 类型 > ( *< 指针名 >) (< 参数表

>)

2) 赋值 < 指针名 > = < 成员函数名 >

( 对象 .*< 指针名 >)(< 参数表 >)( 指向对象的指针 ->*< 指针名 >)(< 参数表>)

一、指向类成员的指针一、指向类成员的指针 2. 指向成员函数的指针

< 类名 >::

< 类名 >::

3) 引用 成员指针运算符

Page 5: 第六章 类和对象 ( 二 )

class A{ public: int fun(int b) {return a*c+b:} A(int i) {a=i;} int c; private: int a;};

1) 定义一个指向类 A 的数据成员 c 的指针 pc:

2) 定义一个指向类 A 的成员函数 fun 的指针 pfun:

int A::*pc = & A::c;

int (A::*pfun)(int) = A::fun;

Page 6: 第六章 类和对象 ( 二 )

[ 例 6.1]void main( ){ A x(8);

int A::*pc; pc = &A::c; x.*pc = 3;

int (A::*pfun)(int); pfun = A::fun;

A *p = &x; cout<<( p->*pfun)(5)<<endl;

}

p->fun(5); x.fun(5);

x.*pfun(5);

x.c =3;

29

class A{ public: int fun(int b) {return a*c+b;} A(int i) {a=i;} int c; private: int a;};

// 注意 * 的位置// 注意 & 的位置

指针 pc

指针 pfun

指针 p

Page 7: 第六章 类和对象 ( 二 )

一、指向类成员的指针二、对象指针和对象引用作函数参数三、 this 指针

§§6.1 6.1 对象指针和对象引用对象指针和对象引用

Page 8: 第六章 类和对象 ( 二 )

二、对象指针和对象引用作函数参数

1) 实现“传址调用”,被调函数中通过改变形参指针所指对象的值来影响实参;2) 只将实参的地址传给形参,不进行副本拷贝, 减少时空开销,提高运行效率;3) 要求 形参:对象指针 实参:对象的地址值

1. 对象指针作函数参数

Page 9: 第六章 类和对象 ( 二 )

[ 例 6.2] #include <iostream.h>class M{ public: M( ) {x=y=0;} M(int i, int j) {x=i; y=j;} void copy(M *m); void setxy(int i, int j) {x=i; y=j;} void print() { cout<<x<<","<<y<<endl; } private: int x, y;};

void main( ){ M p(5,7), q; q.copy(&p); fun(p, &q); p.print( ); q.print( ); }

5, 722, 25

void M::copy(M *m){ x=m->x; y=m->y;}

void fun(M m1, M *m2){ m1.setxy(12, 15); m2->setxy(22, 25);}

Page 10: 第六章 类和对象 ( 二 )

1) 具有对象指针作函数参数的优点,被调函数中通过改变引用的值来直接影响实参;2) 函数参数形式更简单、直接3) 要求 形参:对象引用 实参:对象

二、对象指针和对象引用作函数参数 2. 对象引用作函数参数

Page 11: 第六章 类和对象 ( 二 )

[ 例 6.3] #include <iostream.h>class M{ public: M( ) {x=y=0;} M(int i, int j) {x=i; y=j;} void copy(M &m); void setxy(int i, int j) {x=i; y=j;} void print() {cout<<x<<","<<y<<endl;} private: int x, y;};

void main( ){ M p(5,7), q; q.copy(p); fun(p, q); p.print( ); q.print( ); }

void M::copy(M &m){ x=m.x; y=m.y;}

void fun(M m1, M &m2){ m1.setxy(12, 15); m2.setxy(22, 25);}

Page 12: 第六章 类和对象 ( 二 )

#include<iostream.h>

class Point

{public:

Point(int a, int b)

{ X=a; Y=b; }

void fun(Point &p);

void fun(Point *p);

private:

int X,Y;

};

void Point::fun(Point &p)

{ X=p.X; Y=p.X;

cout<<"fun(Point &p)."<<endl;

}void Point::fun(Point *p)

{ X=p->X; Y=p->Y;

cout<<"fun(Point *p)."<<endl;

}void main( )

{ Point p1(1, 2), p2(3, 4);

p1.fun(p2);

}

分析程序运行结果:

Page 13: 第六章 类和对象 ( 二 )

一、指向类成员的指针二、对象指针和对象引用作函数参数三、 this 指针

§§6.1 6.1 对象指针和对象引用对象指针和对象引用

Page 14: 第六章 类和对象 ( 二 )

三、 this 指针1. 隐含于每个类的成员函数中 ;2. 指向正在被成员函数操作的对象;3. 对象调用成员函数时,编译器先将该对象的地址赋给 this 指针,然后调用成员函数;4. 调用成员函数存取数据成员时,隐含使用 t

his 指针;一般不显示使用 this 指针引用数据成员。

对象指针

Page 15: 第六章 类和对象 ( 二 )

[ 例 6.4]

void main( ){ A a1, a2(3, 4); a1.copy(a2); a1.print( );}

3, 4

#include <iostream.h>class A{ public: A() {a=b=0;} A(int i, int j) {a=i; b=j;} void copy(A &aa); void print() { cout<<a<<","<<b<<endl; } private: int a, b;};

void A::copy(A &aa){ if( this==&aa ) return; *this=aa; }

void A::copy(A &aa){ (*this).a =aa.a; (*this).b =aa.b;}

Page 16: 第六章 类和对象 ( 二 )

[ 例 6.4]

void main( ){ A a1, a2(3, 4); a1.copy(a2); a1.print( );}

#include <iostream.h>class A{ public: A() {a=b=0;} A(int i, int j) {a=i; b=j;} void copy(A &aa); void print() { cout<<a<<","<<b<<endl; } private: int a, b;};

void A::copy(A &aa){ if( this==&aa ) return; *this=aa; }

void A::copy(A &aa){ this->a =aa.a; this->b =aa.b;}

void A::copy(A &aa){ (*this).a =aa.a; (*this).b =aa.b;}

Page 17: 第六章 类和对象 ( 二 )

[ 例 6.4]

void main( ){ A a1, a2(3, 4); a1.copy(a2); a1.print( );}

#include <iostream.h>class A{ public: A() {a=b=0;} A(int i, int j) {a=i; b=j;} void copy(A &aa); void print() { cout<<a<<","<<b<<endl; } private: int a, b;};

void A::copy(A &aa){ if( this==&aa ) return; *this=aa; }

void A::copy(A &aa){ this->a=aa.a; this->b=aa.b;}

void A::copy(A &aa){ a =aa.a; b =aa.b;}

void A::copy(A &aa){ (*this).a=aa.a; (*this).b=aa.b;}

Page 18: 第六章 类和对象 ( 二 )

1. 隐含于每个类的成员函数中 ;2. 指向正在被成员函数操作的对象;3. 对象调用成员函数时,编译器先将该对象的地址赋给 this 指针,然后调用成员函数;4. 调用成员函数存取数据成员时,隐含使用 this 指针;一般不显示使用 this 指针引用数据成员。

三、 this 指针

非静态成员函数有隐含的“ this” 指针(指向对象); 静态成员函数没有隐含的“ this” 指针。因为静态函数属于类,直接操作类中的静态数据成员

所有的成员函数吗?

Page 19: 第六章 类和对象 ( 二 )

§§6.2 6.2 数 组数 组一、对象数组二、指向数组的指针和指针数组

Page 20: 第六章 类和对象 ( 二 )

一、对象数组

1.定义 < 类名 > < 数组名 >[< 大小 >]…

2.赋值 可以被赋初值,也可以被赋值; 数组元素下标:从 0 开始;

数组元素是同一个类的若干对象

Page 21: 第六章 类和对象 ( 二 )

[ 例 6.5]

void main( ){ DATE dates[5]={ DATE(9, 5, 2002), DATE(9, 6, 2002) }; // 赋初值 dates[2]=DATE(9, 7, 2002); // 赋值 dates[3]=DATE(9, 8, 2002); dates[4]=DATE(9, 9, 2002); for(int i=0; i<5; i++) dates[i].print( ); // 引用}

9/5/20029/6/20029/7/20029/8/20029/9/2002

#include <iostream.h>class DATE{ public: DATE( ) {month=day=year=0;} DATE(int m, int d, int y) { month=m; day=d; year=y; } void print( ) { cout<<month<<“/"<<day<<“/"<<year<<endl; } private: int month, day, year;};

Page 22: 第六章 类和对象 ( 二 )

一、对象数组二、指向数组的指针和指针数组

§§6.2 6.2 数 组数 组

Page 23: 第六章 类和对象 ( 二 )

二、指向数组的指针和指针数组

(1)指向一般数组的指针

(2) 指向对象数组的指针

1. 指向数组的指针

< 类型说明符 > (*< 指针名 >) [< 大小 >]

例: int (*pa)[3];

< 类名 > (*< 指针名 >) [< 大小 >]

Page 24: 第六章 类和对象 ( 二 )

[ 例 6.6]#include<iostream.h>int a[3][3]={1, 2, 3, 4, 5, 6, 7, 8, 9};void main( ){ int (*pa)[3](a); for(int i=0; i<3; i++) {

for(int j=0; j<3; j++) cout<<*(*(pa+i)+j)<<" ";

cout<<"\n"; }}

1 2 3

4 5 6

7 8 9

int (*pa)[3] = a;

Page 25: 第六章 类和对象 ( 二 )

[ 例 6.7] class M{ public: M( ) {a=b=0;} M(int i, int j) {a=i; b=j;} void print() { cout<<a<<","<<b<<'\t'; } private: int a, b;};void main( ){ M m[2][4]; // 对象数组 int x=10, y=10; for(int i=0; i<2; i++) for(int j=0; j<4; j++) m[i][j]=M(x+=2, y+=10); // 赋值 M (*pm)[4](m); // 指向对象数组的指针 pc for(i=0; i<2; i++) { for(int j=0; j<4; j++) (*(*(pm+i)+j)).print(); cout<<endl; }}

12,20 14,30 16,40 18,5020,60 22,70 24,80 26,90

M (*pm)[4] =m;

Page 26: 第六章 类和对象 ( 二 )

(1) 一般的指针数组 (2) 对象指针数组

数组元素为指针的数组

二、指向数组的指针和指针数组2.指针数组

< 类型名 > * < 数组名 >[< 大小 >]…

< 类名 > * < 数组名 >[< 大小 >]…

数组元素:指向同一类对象的指针

常用:字符指针数组char * str[10];

Page 27: 第六章 类和对象 ( 二 )

[ 例 6.9]

void main( ){ A a1(7, 8), a2, a3(5, 7); A* b[3]={&a3, &a2, &a1}; // 对象指针数组 for(int i=0; i<3; i++) b[i]->print( );}

5, 70, 07, 8

数组元素:指向 A 类对象的指针

class A{ public: A(int i=0, int j=0) {a=i; b=j;} void print( ); private: int a, b;};

void A::print( ){ cout<<a<<","<<b<<endl; }

Page 28: 第六章 类和对象 ( 二 )

[ 例 6.9]( 我的 )

#include<iostream.h>class A{ public: A(int i=0, int j=0) {a=i; b=

j;} void print( ); private: int a, b;};

void A::print( ){ cout<<a<<","<<b<<endl;

}

void main( ){A c[3]={ A(7, 8), A(5, 7)};

A* b;b=c;

for(int i=0; i<3; i++) (b+i)->print( );}

Page 29: 第六章 类和对象 ( 二 )

§§6.3 6.3 常类型常类型一、一般常量和对象常量二、常指针和常引用三、常成员函数四、常数据成员

经 const 说明的类型,其值不能更新,定义时必须初始化!

Page 30: 第六章 类和对象 ( 二 )

一、一般常量和对象常量1) 简单类型

2) 常数组

1. 一般常量const < 类型 > < 常量名 > = < 值>< 类型 > const < 常量名 > = < 值>

例 : const int x=2;

例 : int const x=2;

const < 类型 > < 数组名 >[< 大小 >]…

< 类型 > const < 数组名 >[< 大小 >]…

数组元素的值不能更新例 : const int a[5]={1, 2, 3, 4, 5};例 : int const a[5]={1, 2, 3, 4, 5};

初始化

Page 31: 第六章 类和对象 ( 二 )

< 类名 > const < 对象名 >const < 类名 > < 对象名 >

例: const A a1(3, 4); // 常对象 a1

例: A const a2(8,19); // 常对象 a2

一、一般常量和对象常量2.常对象(对象常量)

定义常对象时要初始化 , 对象不能被更新class A{ public: A(int i, int j) {x=i; y=j;} private: int x, y;};

对象 a1 、 a2值不能再被更新

Page 32: 第六章 类和对象 ( 二 )

一、一般常量和对象常量二、常指针和常引用三、常成员函数四、常数据成员

经 const 说明的类型,其值不能更新,定义时必须初始化!§§6.3 6.3 常类型常类型

Page 33: 第六章 类和对象 ( 二 )

二、常指针和常引用

1) 指针常量: const 修饰指针时,随位置不同,含义不同!

2) 指向常量的指针:

指针常量 目标不能更改 能更改

1000

指针 目标常量能更改 不能更改

2000

1. 常指针< 类型 > * const< 指针名 >

const < 类型 > * < 指针名>

Page 34: 第六章 类和对象 ( 二 )

1) 指针常量:

2) 指向常量的指针:

指针常量 目标不能更改 能更改

1000

< 类型 > * const< 指针名 >

const < 类型 > * < 指针名>

const 修饰指针时,随位置不同,含义不同!1. 常指针

指针 目标常量能更改 不能更改

3000

二、常指针和常引用

Page 35: 第六章 类和对象 ( 二 )

1. 定义一个指向字符串 string1 的指针常量 ptr1 :

指针 ptr1 *ptr1

不能更改 能更改

2. 定义一个指向字符串常量 string1 的指针 ptr2 :

ptr2 常量 *ptr1

能更改 不能更改

于是 : ptr1=string2; ( ) 但 *ptr1=“abc”; ( )

于是 : *ptr2=“xyz”; ( ) ; 但 ptr2=string2; ( )

char * const ptr1= string1;

const char * ptr2= string1;

Page 36: 第六章 类和对象 ( 二 )

[ 例 6.11] #include<iostream.h>const int N=6; void print(const int *p, int n);void main( ){ int array[N]; for(int i=0; i<N; i++) cin>>array[i]; print(array, N);}void print(const int *p, int n){ cout<<"{"<<*p; for(int i=1; i<n; i++) cout<<","<<*(p+i); cout<<"}"<<endl;}

形参:指向整常量的指针

实参: int 型数组

一个能够被更新的变量使用在一个不能被更新的环境中,不破坏类型保护!

类型适应一种类型的对象能够用于另一种类型的对象使用的环境

Page 37: 第六章 类和对象 ( 二 )

“常引用”所引用对象的值不能被更新!const < 类型说明符 > &< 引用名 > = 初值< 类型说明符 > const &< 引用名 > = 初值

例: double x(6.6); const double &v =x; 则 v=12.3; ( )

注:常指针和常引用往往用作函数的参数,称“常参数”

二、常指针和常引用2. 常引用

Page 38: 第六章 类和对象 ( 二 )

[ 例 6.12]

void main( ){ K k1(8), k2(17); int s=add(k1, k2); // 实参 : 对象 cout<<s<<endl;}

25

class K{ public: K(int i) { k=i;} int setk() const { return k; } private: int k;};

int add(const K &g1, const K &g2){ int sum= g1.setk( ) + g2.setk( ); return sum;}

常引用作函数参数

? 常成员函数删除 const ,理解 this 和常函数

Page 39: 第六章 类和对象 ( 二 )

一、一般常量和对象常量二、常指针和常引用三、常成员函数四、常数据成员

经 const 说明的类型,其值不能更新,定义时必须初始化!§§6.3 6.3 常类型常类型

Page 40: 第六章 类和对象 ( 二 )

三、常成员函数1. 说明格式:

< 类型 > < 函数名 >(< 参数表 >) const;

2. “const” 作函数类型的一部分,函数实现也要带 const ;3. 常成员函数不更新对象的数据成员,也不能调用未经“ const” 修饰的成员函数;

可以用来操作常对象(常量)

Page 41: 第六章 类和对象 ( 二 )

[ 例 6.12]

void main( ){ K k1(8), k2(17); int s=add(k1, k2); cout<<s<<endl;}

class K{ public: K(int i) { k=i;} int setk() const { return k; } private: int k;};

int add(const K &g1, const K &g2){ int sum= g1.setk( ) + g2.setk( ); return sum;}

常引用

只有常成员函数操作常引用;非常引用可以操作常函数

常成员函数

Page 42: 第六章 类和对象 ( 二 )

[ 例 6.13]

void main( )

{ R a(5, 4);

a.print( );

const R b(20, 52);

b.print( );

}

class R

{ public:

R(int r1, int r2) { R1=r1; R2=r2; }

void print( );

void print( ) const;

private:

int R1, R2;

};

void R::print( )

{ cout<<R1<<";"<<R2<<endl; }

void R::print( ) const{ cout<<R1<<";"<<R2<<endl; }

const 可以参与区分函数重载说明

实现

操作常对象 b

Page 43: 第六章 类和对象 ( 二 )

< 类型 > < 函数名 >(< 参数表 >) const; 强调:只有常成员函数才有资格操作“常对象”

三、常成员函数

1. 未经 const 说明的成员函数不能操作“常对象”; 若一个对象说明为“常对象”,则它只能调用常成员函数,不能调用其他成员函数;2. 常成员函数不仅可以用于操作“常对象”,还可以操作“一般对象”。

Page 44: 第六章 类和对象 ( 二 )

[ 例 6.13]

void main( )

{ R a(5, 4);

a.print( );

const R b(20, 52);

b.print( );

}

class R

{ public:

R(int r1, int r2) { R1=r1; R2=r2; }

// void print( );

void print( ) const;

private:

int R1, R2;

};

void R::print( ) const{ cout<<R1<<";"<<R2<<endl; }

说明

实现

允许操作“一般对象”操作“常对象”

Page 45: 第六章 类和对象 ( 二 )

[ 例 6.13]

void main( )

{ R a(5, 4);

a.print( );

const R b(20, 52);

b.print( );

}

class R

{ public:

R(int r1, int r2) { R1=r1; R2=r2; }

void print( );

// void print( ) const;

private:

int R1, R2;

};

void R::print( )

{ cout<<R1<<";"<<R2<<endl; }

不允许操作“常对象”

Page 46: 第六章 类和对象 ( 二 )

一、一般常量和对象常量二、常指针和常引用三、常成员函数四、常数据成员

经 const 说明的类型,其值不能更新,定义时必须初始化!§§6.3 6.3 常类型常类型

Page 47: 第六章 类和对象 ( 二 )

四、常数据成员 const 类型量在对象定义时必须初始化;

通过“成员初始化列表”生成构造函数

类体中不允许对所定义的数据成员进行初始化;常数据成员的初始化方法

Page 48: 第六章 类和对象 ( 二 )

[ 例 6.14]

void main( ){ A a1(100), a2(0); a1.print( ); a2.print( );}

100: 10: 1000 : 10: 0

class A{ public: A(int i); void print( ); const int &r; // 常 int 型引用 private: const int a; // 常 int 型量 static const int b; // 静态常 int 型量};

A::A(int i) : a(i), r(a){ }void A::print( ){ cout<<a<<":"<<b<<":"<<r<<endl; }

数据成员初始化列表 const int A::b= 10; // 静态数据初始化

Page 49: 第六章 类和对象 ( 二 )

§§6.4 6.4 子对象和堆对象子对象和堆对象

2. 初始化 在构造函数中通过“成员初始化表”来初始化子对象;

1. 含义 一个类的成员是另一个类的对象;

一、子对象(对象成员)

Page 50: 第六章 类和对象 ( 二 )

[ 例 6.15]

void main( ){ B b(6,7, 8); b.print( );}

6, 7 8

class B{ public:

B(int i, int j, int k): a(i, j) { b=k; } void print(); private: A a; // 子对象 int b;};

子对象

class A{ public: A(int i, int j) {A1=i; A2=j;} void print() { cout<<A1<<","<<A2<<endl; } private: int A1, A2;};

void B::print( ){ a.print(); cout<<b<<endl; }

子对象调用成员函数

Page 51: 第六章 类和对象 ( 二 )

class B{ public:

B(int i, int j, int k): a(i, j), b(k) { } void print(); private: A a; // 子对象 int b;};

[ 例 6.15] 修改

void main( ){ B b(6,7, 8); b.print( );}

子对象 数据成员

class A{ public: A(int i, int j) {A1=i; A2=j;} void print() { cout<<A1<<","<<A2<<endl; } private: int A1, A2;};

void B::print( ){ a.print(); cout<<b<<endl; }

Page 52: 第六章 类和对象 ( 二 )

• 子对象的初始化 : < 子对象名 >(< 参数表>)

• 常数据成员的初始化• 其它数据成员的初始化

初始化在构造函数中通过“成员初始化表”完成。

一、子对象(对象成员)

Page 53: 第六章 类和对象 ( 二 )

二、堆对象 程序运行中根据需要由 new 建立和由 delete 删除的对象

动态分配内存空间运算符

1) 在堆中建立给定类型的对象,若无初始值,则为缺省值;2) 创建对象时,根据参数调用适当的构造函数;3) 返回值:指针

例 : A *ptr1; ptr1=new A(5, 6);例 : int *p; p=new int; 或 p=new int(5);

new < 类型 > <( 初始值列表 )>

1. 运算符 new

Page 54: 第六章 类和对象 ( 二 )

new 创建数组 :

a) 使用 new 创建数组时:不能指定初始值,其初始值为缺省值;b) 使用 new 创建对象数组时:类中必须定义缺省构造函数。 ( 因为不能指定初始值啊!)

new < 类型 >[< 大小 >]

一般数组 : int *p; p=new int[10];

对象数组 : A *ptr2; ptr2=new A[5];

具有 5 个元素的对象数组

Page 55: 第六章 类和对象 ( 二 )

检验 new 返回的指针,是否分配有效的内存空间

if( ! a1 ) { cout<<“Heap error! \n”; exit(1); }

“new” 返回值 成功:与分配对象类型相匹配的指针不成功 : 空指针 0

例: AA *a1=new AA(1, 2);

Page 56: 第六章 类和对象 ( 二 )

1) 功能:删除使用 new 创建的堆对象或一般类型堆变量;

2) 注意事项:

delete < 指针名 > A *ptr1=new A(5, 6);

delete ptr1;delete [ ] < 指针名 > A *ptr2=new A[5];

delete [ ] ptr2;

2. 运算符 delete

二、堆对象

Page 57: 第六章 类和对象 ( 二 )

void main( )

{

int *p, *q, a=5;

p = new int(10);

q = &a;

cout<<*p<<endl;

cout<<*q<<endl;

delete p;

delete q;

}

使用 delete 运算符时注意事项:

只能用于 new 返回的指针或空指针,不能用于其他指针!

Page 58: 第六章 类和对象 ( 二 )

void main( )

{

int *p, a=5;

p = new int(10);

cout<<*p<<endl;

delete p;

p = &a;

cout<<*p<<endl;

delete p;

}

使用 delete 运算符时注意事项:

一个指针只能使用一次 delete 操作!

delete 只释放指针指向的内存堆单元

Page 59: 第六章 类和对象 ( 二 )

[ 例 6.16]

void main( ) { AA *a1, *a2;

a1=new AA;a2=new AA(5, 6);a1->print( );a2->print( );delete a1;delete a2;

}

Default Constructor.Constructor. 0, 0 5, 6Destructor.Destructor.

void AA::print( ){ cout<<A<<","<<B<<endl; }

class AA{ public: AA( ) { A=B=0; cout<< “Default Constructor.\n"; } AA(int i, int j) { A=i; B=j; cout<<"Constructor.\n"; } ~AA() { cout<<"Destructor.\n"; } void print( ); private: int A, B;};

Page 60: 第六章 类和对象 ( 二 )

[ 例 6.16] 修改 void main() {

AA *a1, *a2;a1=new AA;a2=new AA(5, 6);a1->print( );a2->print( );// delete a1;// delete a2;

}

Default Constructor.Constructor.0, 05, 6

void AA::print( ){ cout<<A<<","<<B<<endl; }

class AA{ public: AA( ) { A=B=0; cout<< “Default Constructor.\n"; } AA(int i, int j) { A=i; B=j; cout<<"Constructor.\n"; } ~AA() { cout<<"Destructor.\n"; } void print( ); private: int A, B;};

只能通过显式使用delete 析构堆对象

Page 61: 第六章 类和对象 ( 二 )

[ 例 6.17]

void main( ){ B *p; double n; char s[80];

p=new B[3];

p[0]=B("ma", 4.8); p[1]=B("wu", 3.6); p[2]=B("li", 3.1);

for(int i=0; i<3; i++) { p[i].getb(s, n); cout<<s<<","<<n<<endl; }

delete [ ] p;}

DefaultDefaultDefault

ConstructorDestructor maConstructorDestructor wuConstructorDestructor li

ma, 4.8 w, 3.6 li, 3.1

Destructor liDestructor wuDestructor ma

class B{ public: B() {cout<<"Default\n";}

B(char *s, double n) { strcpy(name, s); b=n; cout<<"constructor\n"; }

~B( ) { cout<<"Destructor " <<name<<endl; }

void getb(char *s, double &n) { strcpy(s, name); n=b; } private: char name[80]; double b;};

Page 62: 第六章 类和对象 ( 二 )

1) 功能:删除使用 new 创建的堆对象或一般类型堆变量;2) 注意事项:

delete < 指针名 > delete [ ] < 指针名 >

2. 运算符 delete

二、堆对象

a. 用于 new 返回的指针,或空指针;b. 对一个指针只能用一次 delete ;c. 用 delete 删除堆对象时,调用析构函数;d. 指针名前只用一对 [ ] , 忽略括号内数字和维数。

Page 63: 第六章 类和对象 ( 二 )

§§6.5 6.5 类型转换类型转换一、类型的自动隐式转换二、构造函数的类型转换功能三、转换函数

将一种类型的值映射为另一类型的值

Page 64: 第六章 类和对象 ( 二 )

一、类型的自动隐式转换1. 算术运算时,低类型转换为高类型 ;

2. 赋值表达式中,右值转换为左值类型 , 再赋值 ; 例 : long var; var=10;

3. 函数调用时,实参转换为形参类型 , 赋给形参 ;例 : double f1(double d); double f; f=f1(10);

4. 函数返回值时,返回表达式类型转换为函数类型。 double f1(int d) { int m=d*2; return (m); }

Page 65: 第六章 类和对象 ( 二 )

二、构造函数的类型转换功能 单个参数的构造函数具有类型转换功能;

与其参数类型相同的“数值”

“该类对象”转换成

Page 66: 第六章 类和对象 ( 二 )

[ 例 6.19]

void main( ){ A a(5); a=10; a.print( );}

class A{ public: A( ) {m=0;} A(double i) { m=i; } void print() { cout<<m<<endl; } private: double m;};

10

Page 67: 第六章 类和对象 ( 二 )

[ 例 6.19] 修改

void main( ){ A a(5); a =10; a.print( );}

Constructor: 5

Constructor: 10Destructor: 1010Destructor: 10

通过标准数据类型转换,将整型值 10 转换成 double 型;通过单参数构造函数,将 double 型数值转换成 A 类类型;创建匿名对象,赋值后释放。

class A{ public: A() {m=0;} A(double i) { m=i; cout<<"Constructor: "<<m<<endl; } void print() { cout<<m<<endl; } ~A() { cout<<"Destructor: "<<m<<endl; } private: double m;};

Page 68: 第六章 类和对象 ( 二 )

三、转换函数

1) 非静态的成员函数;2) 不能定义为友元函数;3) 无返回值类型4) 不带参数

class < 类名 1>{ public: operator < 类型说明符 2>( ); ……} 函数名 , 目标类型

将 < 类名 1> 的类型转换为 < 类型说明符 2> 指定的类型

—“ 类型强制转换成员函数”

Page 69: 第六章 类和对象 ( 二 )

[ 例 6.20]

5.325

void main( ){ Rational r(5, 8); double d=4.7; d += r; cout<<d<<endl;}

( double(5)/double(8) )+4.7

class Rational{ public: Rational(int d, int n) { den=d; num=n; } operator double(); private: int den, num;};

Rational::operator double(){ return double(den)/double(num);}

函数名 , 目标类型

隐式类型转换

Page 70: 第六章 类和对象 ( 二 )

[ 例 6.20]

void main( ){ Rational r(5, 8); double d=4.7; d += double(r); cout<<d<<endl;}

class Rational{ public: Rational(int d, int n) { den=d; num=n; } operator double(); private: int den, num;};

Rational::operator double(){ return double(den)/double(num);}

显式类型转换

Page 71: 第六章 类和对象 ( 二 )

[ 例 6.20]

void main( ){ Rational r(5, 8); double d=4.7; d += r. operator double( ); cout<<d<<endl;}

class Rational{ public: Rational(int d, int n) { den=d; num=n; } operator double(); private: int den, num;};

Rational::operator double(){ return double(den)/double(num);}

利用对象直接调用成员函数

Page 72: 第六章 类和对象 ( 二 )

1) 非静态的成员函数;2) 不能定义为友元函数;3) 无返回值类型4) 不带参数

class < 类名 1>{ public: operator < 类型说明符 2>( ); ……}

函数名 , 目标类型

将 < 类名 1> 的类型转换为 < 类型说明符 2> 指定的类型

函数的名称即目标类型对本类型的操作数进行转换

有“ this” 指针

Page 73: 第六章 类和对象 ( 二 )

作 业 题作 业 题三 (1) 对象数组的定义、赋初值、赋值

void main( ){ cout<<"Starting1...\n"; A a[3]; for(int i=0; i<3; i++) a[i].Set(2*i+1, (i+1)*2); cout<<"Ending1...\n";

cout<<"starting2...\n"; A b[3]={A(1,2), A(3,4), A(5,6)}; cout<<"Ending2...\n";}

Starting1… Default Constructor called. Default Constructor called. Default Constructor called. Ending1…

Starting2… Constructor: a=1, b=2 Constructor: a=3, b=4 Constructor: a=5, b=6 Ending2…

Destructor called. a=5,b=6 Destructor called. a=3,b=4 Destructor called. a=1,b=2

Destructor called. a=5,b=6

Destructor called. a=1,b=2 Destructor called. a=3,b=4

Page 74: 第六章 类和对象 ( 二 )

三 (2)

void main( ){ B *ptr; ptr =new B[3]; ptr[0] = B( ); ptr[1] = B(5); ptr[2] = B(2, 3); for(int i=0; i<3; i++) ptr[i].Print( ); delete [] ptr;}

class B{ int x, y; public: B( ); B(int i); B(int i, int j); ~B( ); void Print( );};

Default constructor called.Default constructor called.Default constructor called.

Default constructor called.Destructor called.

Constructor1 called.Destructor called.

Constructor2 called.Destructor called.

x=0, y=0 x=5, y=0 x=2, y=3

Destructor called.Destructor called.Destructor called.

Page 75: 第六章 类和对象 ( 二 )

三(3)

void main( ){ const int N=5; A my; my = N; my.Print();}

Constructor called. 0Constructor called. 5Destructor called. 55Destructor called. 5

单参数构造函数的类型转换功能class A{ public: A(int i=0) {m=i; cout<<"Constructor called."<<m<<"\n";} void Set(int i) { m=i; } void Print() const { cout<<m<<endl; } ~A() {cout<<"Destructor called."<<m<<"\n";} private: int m;};

Page 76: 第六章 类和对象 ( 二 )

三 (4)

void main( ){ fun(5); }

Constructor called. 55Destructor called. 5

单参数构造函数的类型转换功能,常参数class A{ public: A(int i=0) {m=i; cout<<"Constructor called."<<m<<"\n";} void Set(int i) {m=i;} void Print() const { cout<<m<<endl; } ~A() { cout<<"Destructor called."<<m<<"\n"; } private: int m;};

void fun(const A &c){ c.Print(); }

常引用常成员函数操作常引用

Page 77: 第六章 类和对象 ( 二 )

三 (5)void main( ){ complex c1; complex c2(6. 8); complex c3(5.6, 7.9); c1.Print(); c2.Print(); c3.Print(); c1 = complex(1.2, 3.4); c2 = 5; c3 = complex( ); c1.Print(); c2.Print(); c3.Print();}

Default Constructor called. Constructor: real=6.8, imag=0 Constructor: real=5.6, imag=7.9

0 + 0i6.8 + 0i5.6 + 7.9i

Constructor: real=1.2, imag=3.4 Constructor: real=5, imag=0 Default Constructor called.

1.2 + 3.4i5 + 0i0 + 0i

Page 78: 第六章 类和对象 ( 二 )

实 验 实 验 三三1.设计一银行账户类的资金往来管理。1)数据包括:账号、姓名、密码、余额;2)实现的操作包括:开户、存款、取款、查询余额、修改密码;编程实现成员函数主体,实现主程序。

实验内容:

Page 79: 第六章 类和对象 ( 二 )

实 验 实 验 三三2.编程实现一个简单的售书程序,其中:

• Book 类包括书名、成本价等信息;• Sales 类包括书对象、售价、销售量等信息,统计销售额和销售利润;

为类建立一些必要的函数,最后统计销售总额和总利润。

实验内容: