790 likes | 937 Views
第六章 类和对象 ( 二 ). § 6.1 对象指针和对象引用 § 6.2 数组 § 6.3 常类型 § 6.4 子对象和堆对象 § 6.5 类型转换. § 6.1 对象指针和对象引用. 一、指向类成员的指针. 二、对象指针和对象引用作函数参数. 三、 this 指针. < 对象 > . * < 指针名 >. < 指向对象的指针 > - > * < 指针名 >. 一、指向类成员的指针. 1. 指向 数据成员 的指针. 定义 < 类型说明符 > * < 指针名 > 赋值 < 指针名 > = & < 数据成员名 >. < 类名 > ::.
E N D
第六章 类和对象(二) §6.1对象指针和对象引用 §6.2数组 §6.3常类型 §6.4子对象和堆对象 §6.5类型转换
§6.1 对象指针和对象引用 一、指向类成员的指针 二、对象指针和对象引用作函数参数 三、 this指针
<对象>.*<指针名> <指向对象的指针> ->*<指针名> 一、指向类成员的指针 1. 指向数据成员的指针 定义 <类型说明符>*<指针名> 赋值 <指针名> =&<数据成员名> <类名>:: <类名>:: • 使用 通过“对象”来引用指针“指向的成员” 成员指针运算符
(对象.*<指针名>)(<参数表>) (指向对象的指针->*<指针名>)(<参数表>) 一、指向类成员的指针 2. 指向成员函数的指针 定义 <类型>( *<指针名>) (<参数表>) 赋值 <指针名> = <成员函数名> <类名>:: <类名>:: • 引用 成员指针运算符
classA { public: int fun(int b) {return a*c+b:} A(int i) {a=i;} int c; private: int a; }; • 定义一个指向类A的数据成员c的指针pc: • 定义一个指向类A的成员函数fun的指针pfun: int A::*pc= &A::c; int (A::*pfun)(int) = A::fun;
p->fun(5); x.fun(5); x.*pfun(5); 指针pc 指针pfun 指针p classA { public: int fun(int b) {return a*c+b;} A(int i) {a=i;} int c; private: int a; }; //注意*的位置 //注意&的位置 void main( ) { Ax(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; } [例6.1] x.c =3; 29
§6.1 对象指针和对象引用 一、指向类成员的指针 二、对象指针和对象引用作函数参数 三、 this指针
实现“传址调用”,被调函数中通过改变形参指针所指对象的值来影响实参;实现“传址调用”,被调函数中通过改变形参指针所指对象的值来影响实参; • 只将实参的地址传给形参,不进行副本拷贝, • 减少时空开销,提高运行效率; • 要求 形参:对象指针 • 实参:对象的地址值 二、对象指针和对象引用作函数参数 1.对象指针作函数参数
#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; }; [例 6.2] void main( ) { Mp(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); } 5, 7 22, 25
具有对象指针作函数参数的优点,被调函数中通过改变引用的值来直接影响实参;具有对象指针作函数参数的优点,被调函数中通过改变引用的值来直接影响实参; • 函数参数形式更简单、直接 • 要求 形参:对象引用 • 实参:对象 二、对象指针和对象引用作函数参数 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; }; [例 6.3] void main( ) { Mp(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); }
分析程序运行结果: void Point::fun(Point&p) { X=p.X; Y=p.X; cout<<"fun(Point &p)."<<endl; } #include<iostream.h> classPoint {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->Y; cout<<"fun(Point *p)."<<endl; } void main( ) { Point p1(1, 2), p2(3, 4); p1.fun(p2); }
§6.1 对象指针和对象引用 一、指向类成员的指针 二、对象指针和对象引用作函数参数 三、 this指针
三、this指针 对象指针 • 隐含于每个类的成员函数中; • 指向正在被成员函数操作的对象; • 对象调用成员函数时,编译器先将该对象的地址赋给this指针,然后调用成员函数; • 调用成员函数存取数据成员时,隐含使用this指针;一般不显示使用this指针引用数据成员。
#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; }; [例6.4] 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 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; }; [例6.4] 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 main( ) { A a1, a2(3, 4); a1.copy(a2); a1.print( ); } void A::copy(A &aa) { this->a =aa.a; this->b =aa.b; }
#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; }; [例6.4] void A::copy(A &aa) { (*this).a=aa.a; (*this).b=aa.b; } void A::copy(A&aa) { if( this==&aa ) return; *this=aa; } void A::copy(A &aa) { a =aa.a; b =aa.b; } void main( ) { A a1, a2(3, 4); a1.copy(a2); a1.print( ); } void A::copy(A &aa) { this->a=aa.a; this->b=aa.b; }
三、this指针 所有的成员函数吗? • 隐含于每个类的成员函数中; • 指向正在被成员函数操作的对象; • 对象调用成员函数时,编译器先将该对象的地址赋给this指针,然后调用成员函数; • 调用成员函数存取数据成员时,隐含使用this指针;一般不显示使用this指针引用数据成员。 • 非静态成员函数有隐含的“this”指针(指向对象); • 静态成员函数没有隐含的“this”指针。因为静态函数属于类,直接操作类中的静态数据成员
§6.2 数 组 一、对象数组 二、指向数组的指针和指针数组
一、对象数组 • 数组元素是同一个类的若干对象 • 定义 • <类名><数组名>[<大小>]… • 赋值 • 可以被赋初值,也可以被赋值; • 数组元素下标:从0开始;
#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; }; [例6.5] void main( ) { DATEdates[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/2002 9/6/2002 9/7/2002 9/8/2002 9/9/2002
§6.2 数 组 一、对象数组 二、指向数组的指针和指针数组
二、指向数组的指针和指针数组 1. 指向数组的指针 • 指向一般数组的指针 • (2) 指向对象数组的指针 <类型说明符> (*<指针名>)[<大小>] 例:int (*pa)[3]; <类名> (*<指针名>) [<大小>]
[例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"; } } int (*pa)[3] = a; 1 2 3 4 5 6 7 8 9
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; }; [例6.7] void main( ) { Mm[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; } } M (*pm)[4] =m; 12,20 14,30 16,40 18,50 20,60 22,70 24,80 26,90
二、指向数组的指针和指针数组 • 指针数组 • 数组元素为指针的数组 (1) 一般的指针数组 (2) 对象指针数组 常用: 字符指针数组 char* str[10]; <类型名> *<数组名>[<大小>]… <类名> *<数组名>[<大小>]… 数组元素:指向同一类对象的指针
classA { public: A(int i=0, int j=0) {a=i; b=j;} void print( ); private: int a, b; }; [例6.9] void A::print( ) { cout<<a<<","<<b<<endl; } void main( ) { Aa1(7, 8), a2, a3(5, 7); A*b[3]={&a3, &a2, &a1}; //对象指针数组 for(int i=0; i<3; i++) b[i]->print( ); } 数组元素:指向A类对象的指针 5, 7 0, 0 7, 8
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( ); } [例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; };
§6.3 常类型 • 经const说明的类型,其值不能更新,定义时必须初始化! 一、一般常量和对象常量 二、常指针和常引用 三、常成员函数 四、常数据成员
例: constint a[5]={1, 2, 3, 4, 5}; 例: intconst a[5]={1, 2, 3, 4, 5}; 初始化 一、一般常量和对象常量 1. 一般常量 • 简单类型 • 常数组 const<类型> <常量名> = <值> <类型>const <常量名> = <值> 例: constint x=2; 例: int const x=2; 数组元素的值不能更新 const<类型> <数组名>[<大小>]… <类型>const <数组名>[<大小>]…
一、一般常量和对象常量 • 常对象(对象常量) <类名>const <对象名> const <类名> <对象名> 定义常对象时要初始化, 对象不能被更新 class A { public: A(int i, int j) {x=i; y=j;} private: int x, y; }; 对象a1、a2值不能再被更新 例:constA a1(3, 4); //常对象a1 例:Aconst a2(8,19); //常对象a2
§6.3 常类型 • 经const说明的类型,其值不能更新,定义时必须初始化! 一、一般常量和对象常量 二、常指针和常引用 三、常成员函数 四、常数据成员
目标 指针常量 1000 不能更改 能更改 目标常量 指针 2000 能更改 不能更改 二、常指针和常引用 1. 常指针 • const修饰指针时,随位置不同,含义不同! <类型>*const<指针名> • 指针常量: • 指向常量的指针: const<类型>* <指针名>
目标 指针常量 不能更改 能更改 目标常量 指针 3000 能更改 不能更改 二、常指针和常引用 1. 常指针 • const修饰指针时,随位置不同,含义不同! <类型>*const<指针名> • 指针常量: 1000 const<类型> * <指针名> • 指向常量的指针:
*ptr1 指针ptr1 不能更改 能更改 常量*ptr1 ptr2 能更改 不能更改 • 定义一个指向字符串string1的指针常量ptr1: char* const ptr1= string1; 于是:ptr1=string2; ( )但*ptr1=“abc”; ( ) • 定义一个指向字符串常量string1的指针ptr2: const char* ptr2= string1; 于是: *ptr2=“xyz”; ( ) ; 但 ptr2=string2; ( )
类型适应 一种类型的对象能够用于另一种类型的对象使用的环境 #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; } [例6.11] 实参:int型数组 形参:指向整常量的指针 一个能够被更新的变量使用在一个不能被更新的环境中,不破坏类型保护!
二、常指针和常引用 2. 常引用 • “常引用”所引用对象的值不能被更新! const<类型说明符>&<引用名> = 初值 <类型说明符>const&<引用名> = 初值 • 例: double x(6.6); • const double&v =x; • 则 v=12.3; ( ) 注:常指针和常引用往往用作函数的参数,称“常参数”
?常成员函数删除const,理解this和常函数 classK { public: K(int i) { k=i;} int setk() const{ return k; } private: int k; }; [例6.12] 常引用作函数参数 int add(constK&g1, constK&g2) { int sum= g1.setk( ) + g2.setk( ); return sum; } void main( ) { K k1(8), k2(17); int s=add(k1, k2); //实参:对象 cout<<s<<endl; } 25
§6.3 常类型 • 经const说明的类型,其值不能更新,定义时必须初始化! 一、一般常量和对象常量 二、常指针和常引用 三、常成员函数 四、常数据成员
三、常成员函数 • 说明格式: <类型> <函数名>(<参数表>)const; • “const”作函数类型的一部分,函数实现也要带const; • 常成员函数不更新对象的数据成员,也不能调用未经“const”修饰的成员函数; 可以用来操作常对象(常量)
classK { public: K(int i) { k=i;} int setk() const{ return k; } private: int k; }; [例6.12] 常成员函数 常引用 int add(constK&g1, constK&g2) { int sum= g1.setk( ) + g2.setk( ); return sum; } 只有常成员函数操作常引用;非常引用可以操作常函数 void main( ) { K k1(8), k2(17); int s=add(k1, k2); cout<<s<<endl; }
classR { public: R(int r1, int r2) { R1=r1; R2=r2; } void print( ); void print( ) const; private: int R1, R2; }; [例6.13] const可以参与区分函数重载 说明 void R::print( ) { cout<<R1<<";"<<R2<<endl; } void main( ) { R a(5, 4); a.print( ); const R b(20, 52); b.print( ); } 实现 void R::print( )const { cout<<R1<<";"<<R2<<endl; } 操作常对象b
三、常成员函数 <类型> <函数名>(<参数表>)const; • 强调:只有常成员函数才有资格操作“常对象” • 未经const 说明的成员函数不能操作“常对象”; • 若一个对象说明为“常对象”,则它只能调用常成员函数,不能调用其他成员函数; • 常成员函数不仅可以用于操作“常对象”,还可以操作“一般对象”。
classR { public: R(int r1, int r2) { R1=r1; R2=r2; } // void print( ); void print( ) const; private: int R1, R2; }; [例6.13] 说明 实现 void main( ) { R a(5, 4); a.print( ); const R b(20, 52); b.print( ); } void R::print( )const { cout<<R1<<";"<<R2<<endl; } 允许操作“一般对象” 操作“常对象”
classR { public: R(int r1, int r2) { R1=r1; R2=r2; } void print( ); // void print( ) const; private: int R1, R2; }; [例6.13] void R::print( ) { cout<<R1<<";"<<R2<<endl; } void main( ) { R a(5, 4); a.print( ); const R b(20, 52); b.print( ); } 不允许操作“常对象”
§6.3 常类型 • 经const说明的类型,其值不能更新,定义时必须初始化! 一、一般常量和对象常量 二、常指针和常引用 三、常成员函数 四、常数据成员
常数据成员的初始化方法 四、常数据成员 • const 类型量在对象定义时必须初始化; • 类体中不允许对所定义的数据成员进行初始化; 通过“成员初始化列表”生成构造函数
class A { public: A(int i); void print( ); constint &r; //常int型引用 private: const int a; //常int型量 staticconst intb; //静态常int型量 }; [例6.14] const int A::b= 10; //静态数据初始化 A::A(int i): a(i), r(a) { } void A::print( ) { cout<<a<<":"<<b<<":"<<r<<endl; } 数据成员初始化列表 void main( ) { A a1(100), a2(0); a1.print( ); a2.print( ); } 100: 10: 100 0 : 10: 0
§6.4 子对象和堆对象 一、子对象(对象成员) • 含义 • 一个类的成员是另一个类的对象; • 初始化 • 在构造函数中通过“成员初始化表”来初始化子对象;
[例6.15] classA { 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; } classB { public: B(int i, int j, int k): a(i, j) { b=k; } void print(); private: Aa; //子对象 int b; }; 子对象 子对象调用成员函数 void main( ) { B b(6,7, 8); b.print( ); } 6, 7 8