Download presentation
Presentation is loading. Please wait.
1
第三章 类与对象 §3—1 面向对象
2
一、面向对象 面向对象本质上是一种自然合理的思维方法,是一种通过模仿人类建立现实世界模型的习惯思维方式和表达方式,运用对象、类、封装、继承、消息、多态性等概念来构造系统的软件开发方法,它包含面向对象的分析、设计、编程、测试和维护等过程。
3
它从研究的客观事物出发,将它们抽象为系统中的对象,作为构成系统的基本单位,并尽可能隐蔽对象的内部细节,再把具有相同属性和服务的对象抽象为类。
从客观事物出发,经过不同层次上的抽象得到基类和它的派生类,派生类继承基类的属性和服务,实现了共享。
4
类中的大多数数据只能用本类的方法进行处理,类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。
向不同对象发送同一消息,可产生不同的行为
5
二、面向对象的三大特性 即封装性、继承性、多态性 1.封装性:是基础
是把对象的属性和服务结合成一个独立的系统单位,并尽可能隐藏对象的内部细节,只保留有限的对外接口使之与外部发生联系,其目的是有效地实现信息隐藏,它是软件设计模块化、软件复用、软件维护的基础
6
对象和类是封装性的体现。 类是对若干对象的抽象描述,对象是它所属类的实例 对象:是用来描述客观事物的一个实体,是问题域中客观事物的抽象表示,是用来构成系统的基本单位,由一组属性和行为构成
7
对象属性:表示客观事物的静态特性,一般用数据表达
对象行为:描述客观事物的动态特性,即事物的行为,一般用函数(方法)来表达 类:是一种用户自定义的抽象数据类型,包含属性和服务两部分,它为该类的所有对象提供一种统一的抽象描述
8
2.继承性:是关键 派生类继承基类的属性和服务,派生类自身还有新的属性和服务 继承机制既可避免公用代码的重复开发,减少代码和数据冗余,又可通过增强一致性来减少模块间的接口和界面 继承有单继承和多继承,继承有传递性
9
3.多态性:是补充 即同一接口,多种方法;相同界面,多种实现 指同一个名字对应着多种不同的行为或实现 或不同对象收到相同的消息时,产生不同的行为
10
多态性有两种: 编译时的多态性:重载,包括函数和运算符重载 运行时的多态性:动态联编,即同一属性或行为在基类及其各个派生类中具有不同的语义 多态性使高层代码只写一次而在低层可多次复用,提高了程序设计的灵活性和效率
11
三、基本术语 1.抽象 对一类具体事物共性的描述,即从一类事物中抽取共同的本质特点成为概念 2.消息 即成员函数的调用
是向对象发出的服务请求,它包含提供服务的对象标识、服务标识以及输入信息和回答信息
12
消息的接收者是提供服务的对象,它对外提供的每一种服务是按消息格式规定好的消息协议,该消息协议就是其服务的具体功能,即通过函数体来实现的
一条完整的消息包含如下内容: ① 消息的接收者:对象标识 ② 服务标识:函数名 ③ 符合消息协议要求的参数:函数实参表
13
§3—2 类的定义 一、类 面向对象程序设计=对象+对象+对象 对象=算法+数据结构 类:
是对某一类对象的抽象,它由概括了一组对象共同性质的数据和函数组成 是一种用户自定义的抽象数据类型,它具有对数据的抽象性、隐藏性和封装性
14
对象: 是某一个类的实例,是对现实世界中真实对象的模拟 现实世界是一个对象的世界,任何对象都具有一定的属性和操作,总能用数据结构与算法两者合一地来描述
15
二、类的定义 1.类的定义 (1)说明部分 用于类中成员作说明,告诉使用者“干什么”: ① 数据成员说明:对象的属性、状态、特征
② 成员函数说明:对象的行为、操作、服务、方法
16
(2)实现部分 用来实现成员函数,告诉使用者“怎么干” 即提供成员函数的函数体
17
2.具体定义格式: class 类名 { public:成员函数和数据成员的说明或实现 protected:成员函数和数据成员的说明或实现 private:数据成员和成员函数的说明或实现 }; 各个成员函数的实现
18
(1)类名:用户自定义的标识符,应有一定英文含义,类名本身就是类型名 (2)类体:“{ }”括起来的部分,凡在其中实现的成员函数均为内联函数
class 类名 { public:成员函数和数据成员的说明或实现 protected:成员函数和数据成员的说明或实现 private:数据成员和成员函数的说明或实现 }; 各个成员函数的实现 说明: (1)类名:用户自定义的标识符,应有一定英文含义,类名本身就是类型名 (2)类体:“{ }”括起来的部分,凡在其中实现的成员函数均为内联函数
19
(3)访问权限修饰符: ① public:公有访问属性,这种成员可以被任意函数访问(使用),提供类的接口功能 ② protected:保护访问属性,这种成员只能被本类的成员函数和友元函数以及派生类中的成员函数和友元函数访问(使用) ③ private:私有访问属性,这种成员只能被本类的成员函数和友元函数访问(使用)
20
(4)当把私有成员的声明放于类体最前时,private可省略,即缺省(默认)访问权限为private
(5)三种访问权限符在类体中的出现顺序可任意,也可出现多次或不出现 (6)在类体中不允许对声明的数据成员进行初始化 (7)在定义类的成员函数时,也可对形参设置默认值。若该成员函数在类外实现,应在原型中给缺省值
21
(8)在类体外实现的成员函数欲定义为内联函数,应用inline显式声明
(9)本类的成员函数,可以直接使用本类定义的所有数据成员和成员函数 (10)成员函数在类外实现时,函数名前必须加类名和作用域运算符,以指定其所属类 类型符 类名 :: 成员函数名(参数表) {函数体}
22
(11)类类型的大小,即由该类定义的对象所占用存储空间的字节数,等于其所有数据成员所占字节数的总和
(12)类中的成员函数允许重载(同名),但同样要求参数个数、参数类型和参数顺序不完全相同 (13)当类的成员函数在类外实现时,在类体中必须提供其原型
23
例1:日期类 class TDate {public: void setDate(int y,int m,int d); int isLeapYear(); void print(); private: int year, month, day; }; void TDate:: setDate(int y, int m, int d) {year=y; month=m; day=d;} int TDate:: isLeapYear() {return (year%4= = 0&&year%100!=0)‖(year%400= =0);} void TDate::print() {cout<<year<<','<< month <<','<<day<<endl;}
24
例2:时钟类 class Clock {public: void setTime(int h=0,int m=0,int s=0) {hour=h; minute=m; second=s;} void showTime() {cout<<hour<<":"<<minute<<":"<<second<<endl;} private: int hour, minute, second; };
25
例3:点类 class TPoint {public: void setPoint(int a=0, int b=0); int getX(){return x;} int getY()(retuen y;} void move (int xOffset, int yOffset); private: int x, y; }; inline void TPoint::setPoint(int a, int b) {x=a; y=b;} inline void TPoint::move(int xOffset, int yOffset) {x+=xOffset; y+=yOffset;}
26
例4:复数类 # include "math.h" class Complex { double real; double imag; public: void init (double r, double i) {real=r;imag=i;} double realComplex() {return real;} double imagComplex() {return imag;} double absComplex() {double t; t=real * real + imag * imag; return sqrt(t); } };
27
例5:圆类 ? 例6:矩形类 ?
28
§3—3 对象的定义 一、对象的定义 对象是类的实例 应先定义类,再定义对象 类似于变量定义,类名本身就是类型名 类名 对象名表; 例:
类名 对象名表; 例: Point p1,p2,*p,& q=p1,r[30]; //一般对象,对象指针,对象引用,对象数组
29
二、对象成员的引用 1.用对象名引用对象成员:用成员运算符“•” 对象名•数据成员名; 或对象名•成员函数名(参数表)
30
2.用对象指针引用对象成员: ① 用成员运算符“->” 对象指针名->数据成员名 或对象指针名->成员函数名(参数表) ② 用成员运算符“•” (* 对象指针名)•数据成员名 或(* 对象指针名)•成员函数名(参数表)
31
三、对象定义的说明 ① 由同一个类所创建的若干个对象的数据结构是相同的,类中的成员函数是共享的
② 由同一个类创建的不同对象的数据成员存储空间各不相同 ③ 每个对象区别于其他同类对象的地方就是依靠它的自身属性,即数据成员的值
32
void print() {cout<<x<<endl;} private: int x; };
例1:# include "iostream.h" class A {public: void set(int m) {x=m;} int f() {return x+2;} void print() {cout<<x<<endl;} private: int x; }; void main() { A a, b; a.set(5); b.set(10); cout<<a.f()<<b.f()<<endl; a.print(); b.print(); } 结果: 712 5 10
33
结果: 10 6 8 16 例2:# include "iostream.h" class B {public:
void s(int m) {x=m;} void f() {x=x*2;} void show() {cout<<x<<endl;} private: int x; }; void main() {B b1,b2,*p,b; b1.s(5); b2.s(3); p=&b; p->s(4); b1.f(); b2.f(); (*p).f(); b1.show(); b2.show(); p->show(); p->f(); (* p).show();} 结果: 10 6 8 16
34
例3:# include "iostream.h" class D {public: int x; void s(int m) {x=m;} int get() {return x;} }; void main() {D d1,d2; D & d=d1; d1.s(3); d2.s(4); d.x=5; cout<<d1.get()<<d2.get()<<endl; //54 d1.x=6; cout<<d1.get()<<d2.get()<<endl; //64 }
35
例4:栈类 # include "iostream.h" const int SIZE=10; class stack {private: char stk[SIZE]; int tos; public: void init() {tos=0;} void push(char ch) {if (tos== SIZE) {cout<<"Stack is full.\n"; return; } stk[tos]=ch; tos++; void main() {stack s1,s2; int i; s1.init();s2.init(); s1.push('a'); s2.push('x'); s1.push('b'); s2.push('y'); s1.push('c'); s2.push('z'); for(i=0; i<3; i++) cout<<s1.pop(); for(i=0; i<3;i++) cout<<s2.pop(); cout<<endl; } char pop() {if(tos==0) {cout<<"Stack is empty.\n"; return 0; } tos --; return stk[tos]; }; 结果: cbazyx
36
例5:# include "iostream.h" class A {public: void s(int m){x=m;} void f(){x=x+2;} void show(){cout<<x<<endl;} private: int x; }; class B void s(int m){x=m;} void f(){x=x*2;} void main() {A a; B b; a.s(3); b.s(4); a.f(); a.show();//5 b.f(); b.show();//8 a.show();//7 }
37
例:# include "iostream.h" class A {public: int y; protected: int x; public: void init(int a, int b){x=a; y=b;} int getx(){return x;} int gety(){return y;} }a,b; void main() {a.init(2,3); b.init(4,5); cout<<a.getx()<<a.gety()<<endl; cout<<b.getx()<<b.gety()<<endl; } 结果: 23 45
38
例:# include "iostream.h" class A {private: int x, y; public: void set(int a, int b){x=a; y=b;} void show(){cout<<x<<y<<endl;} void print(A * p){p->show();} void print(A & d){d.show();} }; void main() {A m,*q; m.set(4,5); q=& m; q->set(2,3); q->print(&m); q->print(q); q->print(m); } 结果: 23
39
例:# include "iostream.h" class A { int x, y; public: void init(int=0,int=0); void f(int a){x=a;} int f(){return x;} void g(int b){y=b;} int g(){return y;} }; void A::init(int c,int d) {x=c; y=d;} void main() {A m, n; m.init();m.f(2); cout<<m.f()<<m.g()<<endl; n.init(3,4);n.g(5); cout<<n.f()<<n.g()<<endl; } 结果: 20 35
40
§3—4 对象的初始化 即在定义对象时,对其数据成员进行设置 一、用普通成员函数进行对象初始化 须显式调用,麻烦且不安全
41
例:# include "iostream.h" class A { int a,b; public: void set(int i,int j) {a=i;b=j;} void show() {cout<<a<<b<<endl;} }; void main() {A a1 ,a2; a1.set(2,3); a2=a1; a1.show();//23 a2.show();//23 }
42
void disp(){cout<<i<<endl;} }; void main() {A m; m.set(2);
例:# include "iostream.h" class A {public: int i; void set(int a){i=a;} void disp(){cout<<i<<endl;} }; void main() {A m; m.set(2); m.disp(); m.i=3; } 结果: 2 3
43
注:对没有定义构造函数的类,其公有数据成员可以用初始值表进行初始化
例:# include "iostream.h" class A {public: char name[10]; int number; }; void main( ) {A a={"zhangsan",20}; cout<<a.name<<","<<a.number<<endl; } 注:对没有定义构造函数的类,其公有数据成员可以用初始值表进行初始化 结果:zhangsan,20
44
二、构造函数 ① 功能:在创建对象时,用给定值将对象初始化。实例化一个类,分配资源 ② 是一个成员函数,其名字与类名相同
③ 通常是由系统自动调用的,常定义于公有部分 ④ 无函数类型,无返回值 ⑤ 可以有参数,故可以重载
45
⑥ 构造函数也可以采用构造成员初始化列表方式对数据成员进行初始化
但若数据成员存放在堆中或数组中,则不能用此法,而只能在构造函数中使用赋值语句 ⑦ 构造函数不能用常规调用方法调用,不可取其地址,不能被继承
46
三、缺省构造函数:即不带形参的构函 ① 若类中用户未自定义任何构函,则系统将自动生成一个默认构函 ② 是构函的一种重载形式,是公有成员
③ 它无参数,是一个空函数
47
④ 系统自动调用它将外部或静态对象的数据成员初始化为0或空
而自动对象的数据成员的值是无意义的(随机的) ⑤ 默认构函可由用户自定义,但格式应为:类名::类名( ){} ⑥ 若程序中已显式定义了构函,无论它是否带形参,系统都不会提供缺省构函,此时若需要缺省构函,必须显式定义
48
四、析构函数 ① 其功能与构函相反,是在释放对象时,用它来做一些清理工作 ② 是一成员函数,其名字与类名相同,且前面加“~”
③ 它无参数,不能重载;也无函数类型,无返回值
49
④ 一个类有且仅有一个析构函数,通常定义于公有部分
⑤ 通常由系统自动调用:对象生存期结束时或用delete释放堆对象时 ⑥ 具有相同作用域和生存期的若干同类对象,其构函调用顺序与析构顺序恰好相反
50
五、缺省析构函数 ① 当一个类未显式定义析构函数时,系统将自动生成一个默认析构函数 ② 其格式为: 类名 :: ~ 类名( ) { }
③ 是公有成员函数
51
例1:日期类 # include "iostream.h" class Date { int month, day, year; int max(int a, int b){return (a>b)?a:b;} int min(int a, int b){return (a<b)?a:b;} public: Date(){month=day=year=1;} Date(int m, int d, int y) {setMonth(m); setDay(d); setYear(y);} int getMonth(){return month;} int getDay(){return day;} int getYear(){return year;} void setMonth(int m) {month=max(1,m); month=min(12,month); }
52
void setDay(int d) {static int MonthDay[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; day=max(1,d); day=min(day, MonthDay[month]); } void setYear(int y) {year=max(1,y);} void show() {static char * MonthName[]={"Zero","January","February","March","April","June","July", "August","September","October","November","December"}; cout<<MonthName[month]<<","<<day<<","<<year; };
53
例2:圆类 # include "iostream.h" class Circle {public: Circle(float radius){r=radius;} ~Circle(){} float getArea() {return 3.14 * r*r;} private: float r; }; void main() {Circle p(5); cout<<p.getArea()<<endl; } 结果:78.5
54
例3:矩形类 # include "iostream.h" class Rectangle {public: Rectangle(int top,int left,int bottom,int right) {itsTop=top; itsLeft=left; itsBottom=bottom; itsRight=right; } ~Rectangle(){} int getArea() const {int width=itsRight-itsLeft; int height=itsTop-itsBottom; return (width * height); private: int itsTop; int itsLeft; int itsBottom; int itsRight; }; void main() {Rectangle r(100,20,50,80); cout<<r.getArea()<<endl; } 结果:3000
55
例:# include "iostream.h" class A {public: A(int m){x=m;cout<<"ConA"<<x<<endl;} A(){cout<<"DefA"<<endl;} ~A(){cout<<"DesA"<<x<<endl;} void show(){cout<<x<<endl;} private: int x; }; void main() {static A a1; A a2(3); a1.show(); a2.show(); } 结果: DefA ConA3 3 DesA3 DesA0
56
例:# include "iostream.h" class A {public: A(int m){x=m;cout<<"ConA"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} void show(){cout<<x<<endl;} private: int x; }; void main() { A a1(3),a2(4),a3(5); a1.show(); a2.show(); a3.show(); } 结果: ConA3 ConA4 ConA5 3 4 5 DesA5 DesA4 DesA3
57
例:# include "iostream.h" class A {public: A(int m){x=m;cout<<"ConA"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} void show(){cout<<x<<endl;} private: int x; }; void main() { A a1(3),a2=4,*p; A & a3=a1; p=&a2; p->show(); a3.show(); } 结果: ConA3 ConA4 4 3 DesA4 DesA3
58
例:# include "iostream.h" class A {public: A(int m){x=m;cout<<"ConA"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} void s(int n){x=n;} void show(){cout<<x<<endl;} private: int x; }; void main() { A a1(3), a2(4); a2.s(5); a1=a2; a1.show(); a2.show(); } 结果: ConA3 ConA4 5 DesA5
59
A(int m, int n){x=m; y=n;}
例:# include "iostream.h" class A {public: A(){x=1; y=2;} A(int m){x=m; y=m;} A(int m, int n){x=m; y=n;} ~A(){cout<<"DesA"<<x<<y<<endl;} private: int x; int y; }; void main() { A a1, a2(3), a3(4,5);} 结果: DesA45 DesA33 DesA12
60
A(int m=1, int n=2){x=m; y=n;}
例:# include "iostream.h" class A {public: A(int m=1, int n=2){x=m; y=n;} void show(){cout<<x<<y<<endl;} private: int x; int y; }; void main() { A a1, a2(3), a3(4,5); a1.show(); a2.show(); a3.show(); } 结果: 12 32 45
61
A(int m){x=m;cout<<"ConA"<<x<<endl;}
例:# include "iostream.h" class A {public: A(int m){x=m;cout<<"ConA"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} private: int x; }; void f() {A a1(3), a2(4);} void main() {f(); A a3(5), a4(6); } 结果: ConA3 ConA4 DesA4 DesA3 ConA5 ConA6 DesA6 DesA5
62
A(int m){x=m;cout<<"ConA"<<x<<endl;}
例:# include "iostream.h" class A {public: A(int m){x=m;cout<<"ConA"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} private: int x; }; void main() { A a1(3), *p; p=new A(4); delete p; A a3(5), a4(6); } 结果: ConA3 ConA4 DesA4 ConA5 ConA6 DesA6 DesA5 DesA3
63
例:# include "iostream.h" class A {public: A(int m){x=m;cout<<"ConA"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} private: int x; }; void f(){A a1(3), a2(4);} void main() { A *p, *q; p=new A(5); q=new A(6); f(); delete p; delete q; A a3(7), a4(8); } 结果: ConA5 ConA6 ConA3 ConA4 DesA4 DesA3 DesA5 DesA6 ConA7 ConA8 DesA8 DesA7
64
A(int m){x=m;cout<<"ConA"<<x<<endl;}
例:# include "iostream.h" class A {public: A(int m){x=m;cout<<"ConA"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} private: int x; }; void f(){A a1(3), a2(4);} void g(){A a3(5), a4(6);} void main() {f(); g(); A a5(7), a6(8); } 结果: ConA3 ConA4 DesA4 DesA3 ConA5 ConA6 DesA6 DesA5 ConA7 ConA8 DesA8 DesA7
65
例:# include "iostream.h" class A {public: A(int m){x=m;cout<<"ConA"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} private: int x; }; void main() { A *p, *q, *r; r=new A(3); q=new A(4); p=new A(5); delete r; delete q; delete p; } 结果: ConA3 ConA4 ConA5 DesA3 DesA4 DesA5
66
例:# include "iostream.h" class A {public: A(int m){x=m;cout<<"ConA"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} private: int x; }; class B B(int n){y=n;cout<<"ConB"<<y<<endl;} ~B(){cout<<"DesB"<<y<<endl;} int y; void main() { A a1(3),a2(4); B b1(5),b2(6);} 结果: ConA3 ConA4 ConB5 ConB6 DesB6 DesB5 DesA4 DesA3
67
A(int m){x=m;cout<<"ConA"<<x<<endl;}
例:# include "iostream.h" class A {public: A(int m){x=m;cout<<"ConA"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} private: int x; }; void main() { A a1(3), a2=4; a1=A(5); A a3(6); } 结果: ConA3 ConA4 ConA5 DesA5 ConA6 DesA6 DesA4
68
void show(){cout<<i<<j<<endl;} private: int i, j; };
例:# include "iostream.h" class A {public: A(int m, int n):i(m),j(n){cout<<"ConA"<<i<<j<<endl;} void show(){cout<<i<<j<<endl;} private: int i, j; }; void main() { A a(3,4); a.show(); } 结果: ConA34 34
69
A(int i,int j,char c[]):m(i),n(j) {strcpy (name, c);}
例:# include "iostream.h" # include "string.h" class A {public: A(int i,int j,char c[]):m(i),n(j) {strcpy (name, c);} void show() {cout<<m<<n<<name<<endl;} private: int m,n; char name[25]; }; void main() { A a(3,4,"zhangsan"); a.show(); } 结果: 34zhangsan
70
A(int i,int j,int k):m(i),n(j) {x=k; cout<<"DesA" <<endl;
例:# include "iostream.h" class A {public: A(int i,int j,int k):m(i),n(j) {x=k; cout<<"DesA" <<endl; cout<<m<<n<<x<<endl; } private: int m,n,x; }; void main() { A a(1,2,3); 结果: DesA 123
71
例:# include "iostream.h" class A { int * p; public: A(int m) {p=new int(2); *p=m;cout<<"ConA"<<*p<<endl; } void show(){cout<<*p<<endl;} ~A(){cout<<"DesA"<<*p<<endl; delete p; }; void main() { A a (3),b(4); a.show(); b.show(); 结果: ConA3 ConA4 3 4 DesA4 DesA3
72
例:# include "iostream.h" class A { int x, y; public: A(int m, int n):x (m), y(n) {cout<<"ConA"<<x<<y<<endl;} int getx(){return x;} int gety(){return y;} ~A(){cout<<getx()<<y<<endl;} }; void main() { A * p[2]={new A(2,3),new A(4,5)}; p[0]->gety(); p[1]->getx(); delete p[0]; delete p[1]; } 结果: ConA23 ConA45 23 45
73
例:改错 # include "iostream.h" class A {public: A(){x=0;} A(int m=1){x=m;} ~A(){} void show(){cout<<x<<endl;} private: int x; }; void main() {A a; //有二义性 a.show(); }
74
六、拷贝构造函数 ① 是一种特殊的构函,是构造函数的另一种重载形式 ② 它只有一个参数,且是本类对象的引用
③ 它通过将一个已知同类对象的值拷贝给一个新对象,来完成对新对象的初始化 即成员级复制或浅复制,把作为参数的对象的数据成员逐个拷贝到目标对象中
75
④ 每个类都必须有一个拷贝构造函数 ⑤ 其名字与类名相同,无函数类型且无函数返回值,由系统自动调用 ⑥ 在下述三种情况下,需调拷贝构函: a.明确表示用一个对象初始化另一个对象时 b.当对象作为函数实参传递给函数形参时 c.当对象作为函数返回值时
76
⑦ 浅拷贝:只拷贝数据成员的值,可采用缺省拷贝构函
深拷贝:既拷贝数据成员的值,也拷贝对象的资源,如:堆内存、打开文件、占有硬件设备服务(如打印机)等 当一个对象创建时,分配了资源;或当一个类需要析构函数来显式析构资源时,则应深拷贝,即自定义拷贝构函,使之既拷贝数据成员值,又拷贝对象资源
77
七、缺省拷贝构造函数 ① 当用户未显式定义拷贝构函时,系统将自动生成一个缺省拷贝构造函数 ② 是公有成员,是构造函数的重载形式
③ 其格式为: 类名 :: 类名(const 类名 & 对象名) {* this=对象名;}
78
{x=a; y=b; cout<<"ConA"<<endl;} A(A & p) {x=p.x; y=p.y;
例:# include "iostream.h" class A {private: int x, y; public: A(int a, int b) {x=a; y=b; cout<<"ConA"<<endl;} A(A & p) {x=p.x; y=p.y; cout<<"Copy"<<x<<y<<endl; } ~A(){cout<<"DesA"<<x<<y<<endl;} void add(){cout<<x+y<<endl;} }; void main() {A m(2,3); A n(m); A k=m; k.add(); n.add(); } 结果: ConA Copy23 5 DesA23
79
例:# include "iostream.h" class B {private: int x; public: B(int y){x=y; cout<<"ConB"<<x<<endl;} B(B & p){x=p.x; cout<<"Copy"<<x<<endl;} ~B(){cout<<"DesB"<<x<<endl;} }; void main() {B m(2); B & n=m; B a=m; B b(m); B c=4; B d=B(5); B *e=&m; c=d;} 结果: ConB2 Copy2 ConB4 ConB5 DesB5 DesB2
80
A(int y){x=y;cout<<"ConA"<<x<<endl;}
例:# include "iostream.h" class A {private: int x; public: A(int y){x=y;cout<<"ConA"<<x<<endl;} A(A &p){x=p.x; cout<<"Copy"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} int getx(){return x;} }; void f(A m){cout<<m.getx()<<"fff"<<endl;} void main() {A n(2); f(n); } 结果: ConA2 Copy2 2fff DesA2
81
例:# include "iostream.h" class A {private: int x; public: A(int y){x=y;cout<<"ConA"<<x<<endl;} A(A &p){x=p.x; cout<<"Copy"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} int get(){return x;} }; void f(A m){cout<<m.get()<<"fff.\n";} void g(A & n){cout<<n.get()<<"ggg.\n";} void h(A * k){cout<<(*k).get()<<"kkk.\n";} void main() {A a(2); f(a) ; g(a); h(&a);} 结果: ConA2 Copy2 2fff. DesA2 2ggg. 2kkk.
82
A(int y){x=y;cout<<"ConA"<<x<<endl;}
例:# include "iostream.h" class A {private: int x; public: A(int y){x=y;cout<<"ConA"<<x<<endl;} A(A &p){x=p.x; cout<<"Copy"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} }; A f(){A m(2); return m;} void main() {A n(3); n=f(); } 结果: ConA3 ConA2 Copy2 DesA2
83
结果: ConA2 ConA6 ConA3 Copy3 DesA3 DesA4 DesA5 例:# include "iostream.h"
class A {private: int x; public: A(int y){x=y;cout<<"ConA"<<x<<endl;} A(A &p){x=p.x; cout<<"Copy"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} void s(int z){x=z;} }; A m(2); A f(){A n(3); return n;} A & g(){m.s(4); return m;} A * h(){m.s(5); return & m;} void main() {A a(6); a=f(); a=g(); A * q=h(); } 结果: ConA2 ConA6 ConA3 Copy3 DesA3 DesA4 DesA5
84
结果: ConA3 Copy3 3 DesA3 ConA2 Copy2 DesA2 2 例:# include "iostream.h"
class A {private: int x; public: A(int y){x=y;cout<<"ConA"<<x<<endl;} A(A & p){x=p.x; cout<<"Copy"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} int get(){return x;} }; void f(A m){cout<<m.get()<<endl;} A g(){A n(2); return n;} void main() {A a(3); A b(a); f(b); b=g(); cout<<b.get()<<endl; } 结果: ConA3 Copy3 3 DesA3 ConA2 Copy2 DesA2 2
85
A(int y){x=y;cout<<"ConA"<<x<<endl;}
例:# include "iostream.h" class A {private: int x; public: A(int y){x=y;cout<<"ConA"<<x<<endl;} A(A &p){x=p.x; cout<<"Copy"<<x<<endl;} ~A(){cout<<"DesA"<<x<<endl;} int g(){return x;} }; A f(A m) {cout<<"ok.\n"; int z=m.g()+5; A n(z); return n; } void main() {A a(2), b(3); A c(a); b=f(c); a=b; cout<<a.g()<<endl; } 结果: ConA2 ConA3 Copy2 ok. ConA7 Copy7 DesA7 DesA2 7
86
例:# include "iostream.h" class A { int * p; public: A(int m){p=new int; *p=m;cout<<"ConA"<<*p<<endl;} ~A(){cout<<"DesA"<<*p<<endl; delete p; } A(A & n){ p=new int; *p=*(n.p); cout<<"Copy"<<*p<<endl; }; void main() {A a(3); A b(a); 注:深拷贝,既拷贝数据,又拷贝资源 结果: ConA3 Copy3 DesA3
87
例:# include "iostream.h" class A { int * p; public: A(int m){p=new int; *p=m; cout<<"ConA"<<*p<<endl; } A(A & n){p=n.p;} ~A(){cout<<"DesA"<<*p<<endl; delete p; }; void main() {A a(3); A b(a); 注:运行将出错,拷贝资源应深拷贝
88
§3—5 特殊类 一、无名类 ① 即没有名字的类 ② 它只能用作一次性声明对象
③ 它不能有构造函数、析构函数和成员函数,也不能作参数传递或作返回值
89
例:# include "iostream.h" class {public: int a, b; int c; }x, y; void main() {x.a=2; x.b=3; x.c=4; y.a=5; y.b=6; y.c=7; cout<<x.a+x.b+x.c<<endl; cout<<y.a+y.b+y.c<<endl; } 结果: 9 18
90
例:# include "iostream.h" class {public: int a, b; private: int c; }x, y; 方法一: void main(){cout<<&x-&y<<sizeof(x)<<endl;} 结果:-1 12 方法二: void main(){cout<<x.a<<sizeof(y)<<endl;} 结果:0 12
91
二、空类 ① 没有显式定义任何成员 ② 空类对象大小不为零,即各对象具有不同的地址 ③ 在程序开发时,常用空类作基类
92
④ 空类中的缺省成员有5种: a.缺省构造函数:类名( ) { } b.缺省析构函数:~类名( ) { } c.缺省拷贝构函: 类名(const 类名 & 对象名){*this=对象名;} d.缺省赋值运算符重载函数: 类名& operator=(const 类名 & 对象名); e.缺省取地址运算符重载函数: 类名*operator & ( ) {return this;}和 const 类名*operator & ( ) const {return this;}
93
例:# include "iostream.h" class A {private: int k; }; const A a; void main() {A b=a; A c; c=b; A * p=& b; const A * q=& a; if(&b==&c)cout<<"equal!\n";else cout<<"not equal!\n"; if(p==q)cout<<"equal.\n";else cout<<"not equal.\n"; } 结果: not equal! not equal.
94
例:# include "iostream.h" class Empty {}; void main() {Empty a, b; if(&a==&b)cout<<"equal!"<<endl; else cout<<"not equal!"<<endl; } 结果: not equal!
95
三、用struct定义类 ① 是C++对C的扩展,它不仅可以有数据成员,还可以有成员函数
② 它只有两类成员:私有成员private和公有成员public(visual C++有protected成员) ③ 在缺省(默认)情况下,结构中的成员是公有的(class类中缺省成员为私有的,这是两者的唯一区别) ④ 是另外一种形式的类,很少用 ⑤ 它可以有构造函数和析构函数
96
例:# include "iostream.h" # include "math.h" struct Complex {private: double real,imag; public: void init(double r, double i){real=r; imag=i;} double realComplex(){return real;} double imagComplex(){return imag;} double absComplex(){return sqrt(real*real+imag*imag);} }; void main() {Complex a; a.init(3,4); cout<<a.realComplex()<<a.imagComplex()<<a.absComplex()<<endl; } 结果:345
97
{ A(int x, int y){a=x; b=y; cout<<a<<b<<"ConA\n";}
例:# include "iostream.h" struct A { A(int x, int y){a=x; b=y; cout<<a<<b<<"ConA\n";} ~A(){cout<<"DesA"<<a<<b<<endl;} private: int a, b; }m(1,2); A n(3,4); void main() {A k(5,6); cout<<sizeof(A)<<endl; } 结果: 12ConA 34ConA 56ConA 8 DesA56 DesA34 DesA12
98
{ void set(int x, int y, int z){a=x; b=y; c=z;}
例:# include "iostream.h" struct A { void set(int x, int y, int z){a=x; b=y; c=z;} void show(){cout<<a<<b<<c<<endl;} int add(){return a+b+c;} protected: int a, b; private: int c; }; void main() {A m; m.set(2,3,4); m.show(); cout<<m.add()<<sizeof(m)<<endl; } 结果: 234 912
99
四、用union定义类 ① 是C++对C的扩展,联合中既可有数据成员,又可有成员函数 ② 其数据成员共享同一段内存,即存储在同一位置上
③ 可以有构造函数和析构函数 ④ 联合的所有成员只能为公有成员(Visual C++中可以有public、protected、private三种成员,缺省为public成员)
100
⑤ 联合不能从其他类继承属性 ⑥ 联合不能作为基类派生子类 ⑦ 联合不能包含任何静态成员 ⑧ 联合成员对象不能拥有自己的构函和析构函数
101
{ A(int x,int y){a=x;b=y;cout<<a<<b<<"conA\n";}
例:# include "iostream.h" union A { A(int x,int y){a=x;b=y;cout<<a<<b<<"conA\n";} ~A( ){cout<<"DesA"<<a<<b<<endl;} protected: int a; private: int b; }m(1,2); A n(3,4); void main() {A k(5,6); cout<<sizeof(A)<<endl; } 结果: 22ConA 44ConA 66ConA 4 DesA66 DesA44 DesA22
102
{ B(int x,int y,int z) {c=z;b=y;a=x;}
例:# include "iostream.h" union B { B(int x,int y,int z) {c=z;b=y;a=x;} void show( ){cout<<a<<b<<c<<endl;} void add( ){cout<<a+b+c<<endl;} int a,b,c; }; void main( ) {B m(1,2,3),n(4,5,6); m.show( ); m.add( ); n.show( ); n.add( ); } 结果: 111 3 444 12
103
五、局部类 ① 是在一个函数体内定义的类 ② 它只能在定义它的函数体内使用,即它被隐藏在定义它的函数体内 ③ 不能在类中说明静态的成员函数
④ 所有成员函数均须在类体内实现 ⑤ 实践中,很少用 ⑥ 目的:减少全局标识符(名字空间,命名冲突)
104
例:# include "iostream.h" void f() { int x(3); class A {public: void set(int y){x=y;} int x; }; A m; m.set(4); cout<<m.x<<x<<endl; } void main(){f();} 结果:43
105
六、嵌套类 ① 是在一个类中定义的类 ② 目的是为了隐藏类名,减少全局标识符,限制类的使用范围,提高类的抽象能力
③ 当它在外围类作用域外使用时,需加外围类名限定 ④ 嵌套类与外围类相互独立,它们只是语法书写格式上的嵌套 ⑤ 当嵌套类的定义内容写于外围类体外时,须加外围类名限定
106
# include "iostream.h" class A {public: class B B(int m){b=m;} void show( ){cout<<b<<endl;} private: int b; }; A(int n){a=n;} void show ( ){cout<<a<<endl;} void f( ){B x(3);x.show( ); A y(4);y.show( ); show( ); } int a; void main( ) {A c(5); c.f( ); A::B d(6); d.show( ); } 结果: 3 4 5 6
107
例:# include "iostream.h" class A {public: class B; A(int m){a=m;cout<<"ConA.\n";} void show( ){cout<<a<<endl;} private: int a; }; class A::B class D; B(int n){b=n;cout<<"ConB.\n";} void show( ){cout<<b<<endl;} int b; class A::B::D {public: D(int c){d=c;cout<<"ConD.\n";} void show( ){cout<<d<<endl;} private: int d; }; void main() {A e(5);e.show( ); A::B f(6); f.show( ); A::B::D g(7); g.show( ); } 结果: ConA. 5 ConB. 6 ConD. 7
108
§3—6 特殊对象 一、临时对象 ① 当函数返回一个对象时,要创建一个临时对象以带回返回值
② 系统调用拷贝构函,将返回对象拷贝到新创建的临时对象中 ③ 创建的临时对象,只在整个创建它们的外部表达式范围内有效 ④ 临时对象在外部表达式结束时析构
109
A(int n=0){a=n; cout<<a<<"ConA.\n";}
例:# include "iostream.h" class A {public: A(int n=0){a=n; cout<<a<<"ConA.\n";} A(A&m){a=m.a; cout<<a<<"Copy.\n";} ~A(){cout<<"DesA"<<a<<endl;} private: int a; }; A f(){A k(3); return k;} void main() {A b; b=f();cout<<"after.\n"; } 结果: 0ConA. 3ConA. 3Copy. DesA3 after.
110
A(int n=0){a=n;cout<<a<<"ConA.\n";}
例:# include "iostream.h" class A {public: A(int n=0){a=n;cout<<a<<"ConA.\n";} A(A & m){a=m.a;cout<<a<<"Copy.\n";} ~A(){cout<<"DesA"<<a<<endl;} int get(){return a;} private: int a; }; A f(){A k(3); return k;} int g(A & c){cout<<"before.\n";return c.get();} void main() {int d=1+g(f()); cout<<d<<"after.\n"; } 结果: 3ConA. 3Copy. DesA3 before. 4after.
111
二、无名对象(匿名对象) ① 即没有名字的对象 ② 可用无名对象初始化一个引用 ③ 可用无名对象拷贝构造一个对象
④ 可用无名对象作实参传递给形参
112
A(int n=0){a=n; cout<<a<<"ConA.\n";}
例:# include "iostream.h" class A {public: A(int n=0){a=n; cout<<a<<"ConA.\n";} ~A(){cout<<"DesA"<<a<<endl;} A(A & m){a=m.a;cout<<a<<"Copy.\n";} int get(){return a;} private: int a; }; void f(A & d){cout<<d.get()<<endl;} void main() {A & b=A(3); //等效为A b=3; A c=A(4); //系统优化为A c=4; f(A(5)); //等效为A t(5); f(t); } 结果: 3ConA. 4ConA. 5ConA. 5 DesA5 DesA4 DesA3
113
void h(){cout<<a<<endl;} private: int a; }; void main()
例:# include "iostream.h" class A {public: A(int x):a(x){} A s(){return A(a+4);} A f(){return A(a+5);} A g(){return A(a+6);} void h(){cout<<a<<endl;} private: int a; }; void main() {A b(3); b.s().f().g().h(); } 结果:18
114
三、堆对象 ① 是在程序运行中,根据需要动态创建的对象 ② 存放于内存堆中,用new分配,用delete释放
③ 创建堆对象时要调构函,释放时要调析构函数 ④ 从堆中分配对象数组,只能调用默认构函,若该类无默认构函,将出错
115
例:# include "iostream.h" # include "stdlib.h" class A {public: A(){cout<<"Default\n";} A(int m, int n){a=m; b=n; cout<<a<<b<<"ConA.\n";} ~A(){cout<<"DesA"<<a<<b<<endl;} private: int a, b; }; int main() {A * p, *q; p=new A(2,3); if(!p){cout<<"allocation failure\n"; return 1;} delete p; q=new A[2]; //堆对象数组 if(!q){cout<<"Heap error!\n"; exit(1);} q[0]=A(4,5); q[1]=A(6,7); delete[]q; exit(0); //等价于return 0; } 结果: 23ConA. DesA23 Default 45ConA. DesA45 67ConA. DesA67
116
例:# include "iostream.h" class A {public: A(int m, int n){a=m; b=n; cout<<a<<b<<"ConA.\n";} ~A(){cout<<"DesA"<<a<<b<<endl;} private: int a,b; }; void main() {A * p[]={new A(2,3),new A(4,5)}; delete p[0]; delete p[1]; //对象指针数组 } 结果: 23ConA. 45ConA. DesA23 DesA45
117
四、子对象 ① 即对象成员,也称类的组合或类的聚集 ② 是指一个类的对象作另一个类的数据成员
③ 内嵌子对象的类(组合类)的构造函数应包含对子对象的初始化。常采用成员初始化列表的方式来初始化子对象 ④ 当创建对象时,其各个内嵌子对象也将被自动创建
118
⑤ 先执行子对象构函,再执行本类构函,析构顺序相反
⑥ 当有多个子对象时,其构函调用顺序取决于类中声明的顺序,而不是构函中冒号后的成员初始化列表顺序
119
⑦ 它体现的是聚合关系,即一个复杂对象可以化解为简单对象的集合,在一个描述复杂事物的类中,可以包含有若干个描述简单事物的类的对象。即它体现了客观世界中对象之间的包含关系
⑧ 只有在定义构函时,才能带成员初始化列表,在构函原型中,不能带成员初始化列表
120
例1:# include "iostream.h" class A {public: A(int x, int y){a=x; b=y; cout<<a<<b<<"ConA.\n";} ~A(){cout<<"DesA"<<a<<b<<endl;} private: int a,b; }; class B B(int i, int j, int k):m(i,j),n(k) {cout<<n<<"ConB.\n";} ~B(){cout<<"ConB"<<n<<endl;} int n; A m; void main() {A c(2,3); B d(4,5,6); } 结果: 23ConA. 45ConA. 6ConB. DesB6 DesA45 DesA23
121
例2:# include "iostream.h" class A {public: class B B(int i):b(i) {cout<<b<<"ConB.\n";} ~B(){cout<<"DesB"<<b<<endl;} private: int b; }; A(int x, int y):c(x), a(y) {cout<<a<<"ConA.\n";} ~A(){cout<<"DesA"<<a<<endl;} int a; B c; void main() {A d(2,3),e(4,5); } 结果: 2ConB. 3ConA. 4ConB. 5ConA. DesA5 DesB4 DesA3 DesB2
122
例:# include "iostream.h" class A {public: A(int x):a(x){cout<<a <<"ConA.\n";} ~A(){cout<<"DesA"<<a <<endl;} private: int a; }; class B B(int i, int j, int k):one(i),two(j),b(k) {cout<<b<<"ConB.\n";} ~B(){cout<<"DesB"<<b<<endl;} A two; A one; int b; void main() {B d(2,3,4); } 结果: 3ConA. 2ConA. 4ConB. DesB4 DesA2 DesA3
123
class D {public: D(int i, int j, int k):e(i,j),d(k) {cout<<d<<"ConD.\n";} ~D(){cout<<"DesD"<<d<<endl;} private: int d; B e; }; void main() {D m(2,3,4); cout<<sizeof(m)<<endl; } 结果: 2ConA. 3ConB. 4ConD. 12 DesD4 DesB3 DesA2 # include "iostream.h" class A {public: A(int x):a(x){ cout<<a <<"ConA.\n";} ~A(){cout<<"DesA"<<a<<endl;} private: int a; }; class B B(int y, int z):c(y),b(z) {cout<<b<<"ConB.\n";} ~B(){cout<<"DesB"<<b<<endl;} int b; A c;
124
# include "iostream.h" # include "math.h" class Point {public: Point(float i, float j):x(i),y(j){} Point(Point & p){x=p.x; y=p.y; cout<<x<<y<<"copy\n";} float getx(){return x;} float gety(){return y;} private: float x, y; }; class Line Line(Point m, Point n):a(m),b(n) {float x=a.getx()-b.getx(); float y=a.gety()-b.gety(); length=sqrt(x*x+y*y); } double getLength(){return length;} Point a, b; double length; void main() {Point p1(6,9), p2(3,5); Line c(p1,p2); cout<<c.getLength()<<endl; } 结果: 35copy 69copy 5
125
cout<<c.getLength()<<endl; } 结果:5
# include "iostream.h" # include "math.h" class Point {public: Point(float i, float j):x(i),y(j){} float getx(){return x;} float gety(){return y;} private: float x, y; }; class Line Line(float m, float n, float e, float f):a(m,n),b(e,f) {float x=a.getx()-b.getx(); float y=a.gety()-b.gety(); length=sqrt(x*x+y*y); } double getLength(){return length;} Point a, b; double length; void main() {Line c(6,9,3,5); cout<<c.getLength()<<endl; } 结果:5
126
# include "iostream.h" class A {public: A(int x){a=x;} int s(){return a;} A g(){return A(a+2);} void h(){cout<<a<<endl;} private: int a; }; class B B(int y, A n):m(n), b(y){} A f(){int k=m.s()+b; return A(k);} int b; A m; void main() {A c(3); B d(4,c); d.f().g().h(); } 结果:9
Similar presentations