380 likes | 587 Views
第三章 类和对象. 要求: 掌握类的设计方法 掌握对象的创建方法. 类-类的定义. 一般形式. 外部程序不可见。只能由该类对象的成员函数、以及被声明为友元的函数或声明为友元的类的对象的成员函数访问. class 类名 { private : 私用数据成员和成员函数 protected : 保护数据成员和成员函数 public : 公用数据成员和成员函数 } ;. 允许该类的派生类访问. 外部程序可见。允许程序中其他函数或其他类的对象的成员函数访问。. 例 3 - 1 复数类设计. 私有数据成员: 实部、虚部;
E N D
第三章 类和对象 要求: 掌握类的设计方法 掌握对象的创建方法
类-类的定义 • 一般形式 • 外部程序不可见。只能由该类对象的成员函数、以及被声明为友元的函数或声明为友元的类的对象的成员函数访问 class 类名 { private: 私用数据成员和成员函数 protected : 保护数据成员和成员函数 public: 公用数据成员和成员函数 }; • 允许该类的派生类访问 • 外部程序可见。允许程序中其他函数或其他类的对象的成员函数访问。
例3-1 复数类设计 • 私有数据成员: 实部、虚部; • 公有成员函数:加、减、乘、除运算、输出; Complex Add(Complex x) { Complex z; z.real=real+x.real; z.imag=imag+x.imag; Return z; } Complex Sub(Complex x) { Complex z; z.real=real-x.real; z.imag=imag-x.imag; Return z; } #include<iostream.h> Class Complex { Private: float real; float imag; Public: Complex(float x=0,float y=0) { real=x; imag=y; } ~complex() {}
例3-1 复数类设计 { z.real=(real*x.real+imag*x.imag)/c; z.imag=(x.real*imag-real*x.imag)/c; return z; } } Void show() { cout<<“real is”<<real; cout<<“imag is”<<imag<<endl; } }; Complex Multi(Complex x) { Complex z; z.real=real*x.rea-imag*x.imagl; z.imag=real*x.image+x.real*imag; return z; } Complex Divide(Complex x) { Complex z; float c=x.real*x.real+x.imag*x.imag; if (c==0) { cout<<“分母为0错!”; exit(0); } else
类-成员变量 • 数据类型 • 任何C++的基本数据类型和用户自定义数据类型 • C++的基本类类型 • 用户自定义类类型(但不能递规) • 访问权限 • 一般设为私有 • 初始化 • 不在定义时完成,创建对象时由构造函数完成 Class student { Private: student x; };
类-构造函数和类的实例化 • 构造函数 • 定义 - 特殊的成员函数。创建类的实例时,系统自动调用,完成对象的初始化赋值工作。 • 设计方法 • 构造函数名与类型完全相同,不能有返回值 • 参数用来传递定义对象时的初始值,可以为空。 • 允许有默认值,给出所有参数的默认值,可以定义数组对象 • 访问权限为public • 可以重载 • 参数可以是一个已有初始化数值的对象,这种构造函数称作拷贝构造函数。
类-构造函数和类的实例化 • 构造函数 • 两种格式 Complex(float x=0, float y=0) { real=x; imag=y; } Complex(float x=0, float y=0): rea(x),imag(y){} • 两种位置 • 类定义体外定义 • 类定义体内定义 Complex::Complex(float x=0,y=0):real(x),imag(y){}
类-构造函数和类的实例化 • 类的实例化 • 格式 类名 对象名(实参表) 例: Complex x(1,2), y(3,4); Complex x,y; 说明:用默认值初始化对象时,或没有参数时,对象名后边一定不能有括号! • 实例化时,为对象的成员变量分配内存空间 P52, 如图3.1
例3-2 构造函数重载、拷贝构造函数 //Date.h #include <iostream.h> class Date { private: int month; int day; int year; public: //构造函数,内联函数方式,带有默认初始值 Date(int m = 1, int d = 1, int y = 2000):month(m), day(d), year(y){} Date(Date &d) //拷贝构造函数 {month = d.month; day = d.day; year = d.year;} ~Date(void) {} void PrintDate(void) const {cout << month << "-" << day << "-" << year << endl;} };
例3-2 构造函数重载、拷贝构造函数 #include "Date.h" void main(void) //测试主函数 { Date today(8, 23, 2001); //带初始值的对象定义 Date someDay; //使用默认值的对象定义 Date someDay2(today); //使用拷贝构造函数的对象定义 Date someArrayDay[4]; //使用默认值的数组对象定义 today.PrintDate(); //打印初始值日期 someDay.PrintDate(); //打印默认值日期 someDay2.PrintDate(); //打印对象today的日期 someArrayDay[0].PrintDate(); //打印默认值日期 someArrayDay[3].PrintDate(); //打印默认值日期 } 所有参数采用默认值,或构造函数为空,对象后不带括号
类-成员函数和对象的消息 • 成员函数 • 定义 -为外部程序提供一定服务的公共程序接口 • 访问权限(private, public、protected) • 一般格式 返回类型 类名::成员函数名(形参表) { 函数体; }
类-成员函数和对象的消息 Class Comlex { …… Complex Add(Complex x) ; …… } • 成员函数重载 • 设计(声明和实现) • 内联函数方式: 声明和实现都在类定义内 • 外联函数方式:声明在类内,实现在类外 Complex Comlplex::Add(Complex x) { Complex z; z.real=real+x.real; z.imag=imag+x.imag; Return z; }
类-成员函数和对象的消息 • 通过对象调用成员函数 • 格式: 对象名. 成员函数(实参表) 例:void main(void) { Complex x(1,1), y(2,2), z1; z1=x.Sub(y); z1.show(); }
例3-3 成员函数重载 #include<iostream.h> Class Complex { Private: float real; float imag; Public: Complex(float x=0,float y=0): real(x),imag(x);{} ~complex() {} Complex Add(const Complex x)const; Complex Add(const float x)const; void show(void) const; }; Complex Complex::Add(const Complex x)const { return Complex(real+x.real, image+y.imag); } Complex Complex::Add( const float x) const { return Complex(real+x,imag); } Void Complex::show(void)const { cout<<“real is”<<real; cout<<“imag is”<<image<<endl; } 成员函数只能读取当前对象的成员变量,但不能修改。 该参数在成员函数内不能被修改
类-成员函数设计原则 • 一般采用成员函数设计成外联函数。 • 当成员函数的某个参数在函数体内不会或不应该被修改时,用const关键字修饰。 • 当成员函数只能读取类中成员变量,但不能修改时,用const修饰该成员函数。 • 成员函数的输出型参数,应设计成引用类型。
类-析构函数 • 定义 • 特殊的成员函数,每当对象运行到超出作用域时,系统都自动调用析构函数。 • 格式:与类同名,不带参数,无返回值 外联实现: ~ 类名(void) 空析构: ~类名(){} • 一般包含delete语句,也可以是空函数 • 作用 • 释放程序中用new申请的动态内存空间。 • 调用delete运算符时,系统自动定义析构函数,完成一些特殊扫尾工作。
例3-4 析构函数 #include<iostream.h> #include<stdlib.h> Class Array { Private: double *arr; int size; Public: Array(int sz=0); ~Array(void); }; Array::Array(int sz) { if(sz<=0) { cout<<“参数错“<<endl; exit(0); } size=sz; arr=new double[size]; } Array::~Array(void) { delete[]arr; } Void main(void) { Array a(10); }
对象-定义 • 对象的创建方法 • 用户定义,系统自动调用构造函数给对象成员变量赋初值。 类名 对象名(参数); 类名 对象名; 类名 对象名[N]; • 需要时调用new操作符建立 Date *p; p=New Date; delete p; • 引用对象的成员 • <对象名>.<成员> • <指向对象的指针>.<成员> p->month
例3-5 对私有成员变量的设置 #include<iostream.h> #include<complex.h> Void main(void) { Complex x(1,2),y(3,4),z; z=x.Add(y); x.real=10; z.show; } 外部程序定义的对象无权访问类的私有成员变量 调用无参数成员函数,也要带()
例3-5 对私有成员变量的设置 //complex.h #include<iostream.h> Class Complex { Private: float real; float imag; Public: Complex(float x=0,float y=0): real(x),imag(x);{} ~complex() {} …… Float getReal(void)const; Float setReal(const float x); }; Float Complex:: getReal(void) { return real; } Float Complex::setReal(const float x) { real=x; } Void main(void) { Const Complex x(1,2); Complex y, z; x.setReal(3); y.setReal(3); z=x.Add(y); cout<<“z real part is”<< z.getReal();<<endl; } Const对象只能通过构造函数一次初始化赋值
例3-6 创建动态对象 #include”complex.h> Void main(void) { Complex z; complex *x=new complex(1,2); complex *y; y=new complex(3,4); z=x->Add(*y); cout<<“z real part is :”<<z.getReal()<<endl; delete x; delete y; }
对象成员变量 • 整体-部分模式实现 • 定义表示部分概念的类,也称内层类 • 定义表示整体概念的类,也称外层类 • 在整体类中有一个成员变量,它的类型是部分概念类。称该成员变量为子对象 • 整体类构造函数设计 • 显示调用子对象的拷贝构造函数为子对象赋初值 • 显示调用子对象的构造函数为子对象赋初值
例3-6 整体-部分模式实现 class Line { private: Point a; Point b; public: Line(int X1, int Y1, int X2, intY2): a(X1, Y1),b(X2, Y2){} Line(Point &aa, Point &bb):a(aa),b(bb) {} ~Line(void){} void ShowA(void)const { cout<<“a point is (“<<a.Get() <<“,”<<a.GetY()<<“)”; } }; #include<iostream.h> #include <graphics.h> class Point { private: int x; int y; public: Point(int iniX, int iniY) {x = iniX; y = iniY;} Point(Point &c):x(c.x),y(c.y){} ~Point(void){} int GetX(void)const { return x; }…… };
例3-6 整体-部分模式实现 #include”……” Void main(void) { Line myLine1(1,1,5,5); myLine1.ShowA(); myLine1.ShowB(); Point a(10,10),b(50,50); Line myLine2(a,b); myLine1.ShowA(); myLine1.ShowB(); }
例3-7 class Point { private: int x; int y; public: Point(int iniX, int iniY): x(iniX), y(iniY){cout << "类Point构造函数调用" << endl;} Point(Point &a): x(a.x), y(a.y){cout << "类Point拷贝构造函数调用" << endl;} ~Point(void){cout << "类Point析构函数调用" << endl;} }; class Line { private: Point a; Point b;
例3-7 public: Line(int iniX1, int iniY1, int iniX2, int iniY2): a(iniX1, iniY1), b(iniX2, iniY2) {cout << "类Line构造函数1调用" << endl;} Line(Point &aa, Point &bb): a(aa), b(bb) {cout << "类Line构造函数2调用" << endl;} ~Line(void) {cout << "类Line析构函数调用" << endl;} }; void main(void) { cout << "构造函数调用过程:" << endl; Line myLine(1,1,5,5); Point a(1,1), b(5,5); Line myLine2(a, b); cout << "析构函数调用过程:" << endl; }
内部类 • 定义 -当一个类只为另一个类服务时,把它定义在另一个类中,并将其称作内部类,封装有内部类的类称作外部类。 • 规则 • 内部类对外部程序不可见,外部程序不能用它来定义对象 • 外部类无法直接访问内部类的私有成员 • 内部类无法直接访问外部类的私有成员
例3-8 用内部类方式设计线段类。 Public: Line(int X1=0, int Y1=0, int X2=0, int Y2=0): a(X1, Y1), b(X2, Y2){} ~Line(void){} void ShowA(void)const { cout<<“a point is:(“<<a.x<< “,”<<a.y<<“)”<<endl; } …… }; Void main(void) { Point a(10,10),b(50,50); Line myLine(0,10,50,50); myLine.ShowA(); myLineShowB(); } #include<iostream.h> Class Line { class { public: int x; int y; public: Point(int iniX=0, int iniY=0): x(iniX), y(iniY){} ~Point(void){;} }; Private: point a; point b;
static成员 • static 变量 • static变量在编译时分配内存空间,直到整个程序(即主程序)执行完才撤消。 • static变量在编译时进行初始化。如果用户不给初始化值,编译程序自动给出 Main() { int a=2, i; for(i=0;i<3;i++) { printf(“%d”,f(a)); } } f ( int a) { int b=0; static int c=3; b=b+3; c=c+3; Return(a+b+c); }
static成员变量 • 引入原因 • 有些特殊的数据成员为某个类的所有对象所共享,也就是它不是属于具体的对象,而是属于整个类。 • 定义 • 成员变量前加static关键字,成为static成员变量 • 初始化赋值 • 不能用构造函数初始化赋值; • 不能放在主函数中初始化; • 在程序定义该类的任何对象之前,对类中的static数据成员单独初始化; • 文件范围内使用下边语句格式进行初始化: <类名>::<static数据成员名 >= <初始化值>;
Static成员函数 • 引入原因 - 对static数据成员的访问。 • 定义 - 函数定义前加static关键字 - 一般为公有,也可以定义为私有 • 调用 <类名>::<static 成员函数名>(<参数表>)
例3-9 static成员变量 class Employee { private: char name[30]; float salary; static float allSalary; Public: Employee(char *n, float s) { strcpy(name, n); salary = s; allSalary = allSalary + salary; } ~Employee(void) { allSalary = allSalary – salary; } static float GetAllSalary(void) { return allSalary; } }; Float Employee::allSalary = 0; Void main(void) { Employee e1("张", 100); Employee e2("王", 200); Employee e3("李", 300); float all; all = Employee::GetAllSalary(); cout << "AllSalary = " << all << endl; }
4.7 自引用对象指针this • 当用户创建对象时,c++系统为该对象建立了一个this指针,各个对象的this指针指向对象的开始地址 • This指针可以用来表示当前对象 • this指针一般在成员函数中使用,通过this指针调用数据成员。例如:在Date类的构造函数中 Date::Date(int month, int day, int year) { this->month = month; this->day = day; this->year = year; }
例3-8 设计举例-银行贷记卡系统 • 设计要求 • 客户存款、取款和转帐,允许客户取款时透支(即欠款) • 客户余额输出采用类似3元3角1分这样的格式 • 设计一个主程序进行基本情况演示 • 设计分析 • 贷记卡类: • 成员变量:客户帐号、姓名、余额 • 成员函数:存款、取款、转帐、输出 • 余额类
Void Money::Add(const float x) { amount=amount+x; } Void Money::Sub(const float x) { amount=amount-x; } Void Money::Print(void)const { float temp=amount; if(amount>=0) { cout<<“余额:”; } else { cout<<“欠款:”; temp=-temp; } //Account.h #include<string.h> #include<math.h> #include<iostream.h> Class Money { Private: float amount; Public: Money(float a=0):amount(a) {} ~Money() {} void Add(const float x); void Sub(const float x); void Print(void)const; };
~Account(){} Void Add(const float x); Void Sub(const float x); Void transfer(Account &a, const float x); Void Print(void)const; }; Void Account::Add(const float x) { remains.Add(x); } Void Account::Sub(const float x) { remains.Sub(x); } Void Account::transfer(Account &a, const float x) { remains.Sub(x); a.remains.Add(x); } int yuan=int(temp); cout<<yuan<<“元”; int jiao=int((temp-yuan)*10); cout<<jiao<<“角”; int fen=int(ceil(temp*100- yuan*100.0-jioa*10.0)); cout<<fen<<“分”<<endl; } Class Account { Private: long accountNo; char name[30]; Money remains; Public: Account(long a,char *n,Money r): accountNo(a),remains( r) { strcpy(name,n); }
Void Account::Print(void)const { cout<<“姓名:”<<name<<endl; cout<<“帐号:”<<accountNo<<endl; remains.Print(x); } #include”Account.h” Void main(void) { Accounta1(100000,”张三“,Money(3.31)); Accounta2(100001,”李四”,Money(40.42)); Accounta2(100002,”王五”,Money(40.42)); a1.transfer(a2,100); a2.Add(50); a3.Sub(100); a1.Print(); a2.Print(); a3.Print(); }
作业 • P88, 3.28,3.29,3.30, 3.32, 3.33