420 likes | 660 Views
第 3 章 类和对象. 主要内容包括: 1. 类的定义、调用 -- 类的定义 数据成员的定义 成员函数定义 (内联函数) -- 类的调用 (一般调用、 动态调用 ) 2. 对象的初始化( 构造和析构函数 ) 3. 数据成员( const 、 static 、动态、 对象成员 ) 4. 类的调用( 对象数组 、 const 对象和 const 对象成员 5. this 指针. 3.1 定义类. 类的基本结构: class 类名 { private:
E N D
第3章 类和对象 主要内容包括: 1. 类的定义、调用 -- 类的定义 数据成员的定义 成员函数定义(内联函数) --类的调用(一般调用、动态调用 ) 2. 对象的初始化(构造和析构函数) 3. 数据成员(const、static、动态、对象成员) 4. 类的调用(对象数组、const对象和const对象成员 5. this指针
3.1 定义类 • 类的基本结构: class 类名 { private: //私有数据成员和成员函数 类体:进行属性 public:和方法的定义 //公有数据成员和成员函数 protected: //保护数据成员和成员函数 }; private、public和protected表示访问权限,不是每一个类同时都需具备这三种。
定义类—访问权限 • 访问权限限制了外界对类的数据和成员函数的访问; 公有类型(public)声明了对类的外部接口,所有来自外部的访问通过接口进行; 私有类型(private)只允许本类的成员函数来访问,类外部的访问都是非法的; 保护类型(protected)介于公有和私有类型之间,对除本类及派生类以外的类不可访问。
定义类 例:定义一个时钟类,能设置时间和显示时间。 class Clock { private: int Hour,Minute,Second; public: void SetTime(int New_Hour,int New_Minute,int New_Second); void UpdateTime();//刷新 void ShowTime(); };
定义类 时钟类的形象描述: SetTime UpdateTime ShowTime int hour; int minute; int second;
定义类-数据成员的定义 • 数据成员(成员变量)定义类似于变量的定义。 • 数据成员一般定义为私有.
定义类-数据成员的定义 • 数据成员不能在定义时进行初始化。如下是错误的做法: class Clock { private: int Hour=12,Minute=1,Second=30; public: void SetTime(int New_Hour,int New_Minute,int New_Second); void UpdateTime(); void ShowTime(); };
定义类-成员函数的定义 • 类的成员函数是对类中的数据的操作,同时作为外部数据成员的接口,代表了类的对 象的行为。 • 成员函数的声明在类内,函数原型: 函数返回值类型 函数名(参数表); • 成员函数的实现可以在类内,也可以在类外。
定义类-成员函数的定义 在类体内声明成员函数,在类体外实现(用::加以限定) void Clock::ShowTime() { cout<<Hour<<":"<<Minute<<":"<<Second<<endl; } void Clock::SetTime(int New_Hour,int New_Minute,int New_Second) { Hour=New_Hour; Minute=New_Minute; Second=New_Second; }
定义类-成员函数的定义 简短的成员函数可以直接在类体内实现 class Clock { private: int Hour,Minute,Second; public: void SetTime(int New_Hour,int New_Minute,int New_Second); void ShowTime() { cout<<Hour<<":"<<Minute<<":"<<Second<<endl ; }; };
定义类-成员函数的定义 类外定义的内联函数 inline void Clock :: UpdateTime( ) { Second++; if( Second==60) { Second=0; Minute++; }if( Minute==60) { Minute=0; Hour++; } if( Hour==24 ) { Hour=0; }} 内联函数:类内定义的函数和inline限制的类外定义的函数。
类的内联函数 • 在类的内部定义的成员函数 • 对频繁调用的成员函数,定义为内联函数可以减少开销,而如果代码较长应在类外定义,只需定义时加上inline。
类的实例化 • 定义了一个类,就定义了一个新的数据类型,对象(实例)就是这个数据类型的变量。 Clock beginClock; Clock*endClock;
已定义类的调用 • 对类进行实例化(定义对象)后,就可以对类的对象的成员函数进行调用 • 成员函数的调用形式: 对象名 .函数名(实参表); 对象指针->函数名(实参表);
已定义类的调用 例:调用前面定义的Clock类 #include <iostream.h> #include “Clock.h” //包含定义类的头文件 void main() { Clock beginClock; //生成一个Clock类的实例 beginClock . SetTime(9,55,01); //调用类的成员函数 beginClock .ShowTime(); Clock*endClock; endClock =new Clock; //Clock * endClock =new Clock; endClock ->SetTime(11,30,0); endClock ->ShowTime(); delete endClock; }
3.2 对象的初始化 • 定义类时不能给类的数据成员赋初值,因为类是一个抽象的概念,无值可言 如下是错误做法: class Clock { private: int Hour=0,Minute=0,Second=0; public: void SetTime(int New_Hour,int New_Minute,int New_Second); void ShowTime(); };
对象的初始化 • 在声明对象的时候给它的数据成员赋初值,称为对象的初始化 注:变量初始化int a=1;或int a(1); Clock EndClock; Clock BeginClock(9,55,0); • 对象的初始化由构造函数完成 Clock(){}; Clock(int New_Hour,int New_Minute,int New_Second){…}; Clock(int NewH=0,int NewM=0,int NewS=0) {…}; • 定义在公有部分;构造函数名与类名同;没有返回值; • 构造函数可以重载: • 在一个类中可以声明多种形式的构造函数;
对象的初始化—构造函数 class Clock { private: int Hour,Minute,Second; public: Clock(int New_Hour,int New_Minute,int New_Second){…}; Clock(){}; Clock(int NewH=0,int NewM=0,int NewS=0) {…}; void SetTime(int New_Hour,int New_Minute,int New_Second); void ShowTime(); }; • 构造函数在定义类的对象时由系统自动调用; Clock BeginClock(9,55,0);//自动调第一或第三个构造函数 Clock EndClock;//自动调用第二或第三个构造函数
对象的初始化—构造函数 • 不显式声明,系统自动生成一个不做任何事的构造函数; class Clock { private: int Hour,Minute,Second; public: void SetTime(int New_Hour,int New_Minute,int New_Second); void ShowTime(); }; Clock EndClock;
对象的初始化—构造函数 • 显示声明了构造函数,默认构造函数不起作用,就要按声明的构造函数形式进行调用; class Clock { private: int Hour,Minute,Second; public: Clock(){}; //不可少 Clock(int New_Hour,int New_Minute,int New_Second){…}; void SetTime(int New_Hour,int New_Minute,int New_Second); void ShowTime(); }; Clock BeginClock(9,55,0); Clock EndClock;
析构函数 • 析构函数的作用:对象使用结束时进行的清理工作(如内存空间的释放) • 如果不显式定义,系统自动生成一个不做任何事的析构函数 • 如果类中用new动态申请了内存空间,则析构函数中应用delete释放内存空间 • 析构函数唯一,定义为公有的,由系统自动调用 • 析构函数的定义格式
例:动态数据成员、构造函数、析构函数的使用例:动态数据成员、构造函数、析构函数的使用 #include <iostream.h> class Circle { private: int r ; double *s; public: Circle(int New_R){ r=New_R; } void ShowArea( ){ s=new double; *s=3.14*r*r ; cout<<"The area:"<<*s; } ~Circle(){ delete s; } }; void main() { int n=9; Circle *myCircle=new Circle(n); myCircle->ShowArea(); delete myCircle; }
例:构造函数与析构函数的使用 注:测试加上构造函数和析构函数前后调用的情况 #include <iostream.h> class Circle { private: int r ; double s; public: Circle(){}; Circle(int New_R){r=New_R;} void Set_R(int New_R){ r=New_R; } void ShowArea( ){ s=3.14*r*r ; cout<<"The area:"<<s; } ~Circle(){}; }; void main() { int n(9); Circle myCircle; myCircle.Set_R(n); myCircle.ShowArea(); }
3.3 数据成员 • 1. 一般数据成员(略) • 2. 常(const)数据成员 • 3 .静态(static)数据成员 • 4.动态数据成员(略) • 5.对象成员
数据成员—const数据成员 class Point { const int n; public: Point(int k ) : n( k) { } void print(){ cout<<"n="<<n<<endl; } }; void main() { Point s(20); s.print( ); }
数据成员—静态数据成员--类间共享 • 对某个类所有对象都共同享有的成员 • 主要是解决同一个类不同对象间的数据共享问题 • 静态数据成员的定义格式:static <数据类型> <变量名>; • 静态数据成员的使用方法:初始化格式在类外进行 <类型> <类名> ::<静态数据成员>=<值>; 引用静态数据成员格式 (1)如果定义为public,则可直接引用,格式为: <类名>::<静态数据成员> (2)如果定义为private,则只有通过接口函数引用
数据成员—静态数据成员 例:统计一个类产生的对象的总数 class Student { public: Student(){CountS++;} static int CountS; //定义为公有属性 }; int Student::CountS=0; //初始化 void main() { Student Student1,Student2; cout<<"The Number :"<<Student::CountS; } (引用)
数据成员—静态数据成员 class Student { public: Student(){CountS++;} int GetC(){return CountS;} //可将其定义为静态成员函数 private: static int CountS; //定义为私有 }; int Student::CountS=0; void main() { Student Student1,Student2; cout<<"The Number :"<<Student1.GetC();}
class Circle { private: int r ; double s; static int Cout; public: Circle( ) { cin>>r; Cout ++ ; } Circle( int New_R ){ r=New_R; Cout++; } static int Get_C( ){ return Cout; } ~Circle(){ }; }; int Circle::Cout=0; void main() { Circle myCircle; Circle myCircle1(2); cout<<"the Cout:"<<Circle::Get_C()<<endl; }
数据成员—对象成员 • 定义了一个类,就定义了一个新的数据类型; • 可以用其他类的对象作为一个类的数据成员,即对象成员--类嵌套; • 类嵌套实现复杂的对象由比较简单的对象以某种方式组合而成。 例:class Person{ char PersonName[30]; char HomeAddr[60]; Date Birthday; public: Person(char *name,char *addr,int mn,int dy,int yr); }
数据成员—对象成员 • 对象成员的关键问题是如何初始化,具体做法是在引用类的构造函数参数表后写上冒号:对象成员名及(初值表): 例: Person::Person(char *name,char *addr,int mn,int dy,int yr):Birthday(mn,dy,yr) { strncpy(PersonName,name,30); strncpy(HomeAddr,addr,60); }
3.4 类的调用 • 一般调用(略) • 动态调用:指针调用(略) • 数组调用:定义对象数组 • const对象
类的调用—对象数组 • 定义了一个类后,可以如普通数组一样使用类来定义一组对象—对象数组;例: Clock(int New_Hour,int New_Minute,int New_Second); Clock(){}; Clock(int NewH=0,int NewM=0,int NewS=0); Clock myclock[3];//三个对象,缺省构造函数 Clock myclock[]={Clock(9,55,0),Clock(11,30,0)}; //2个对象,调带三个参数的构造函数,初值分别为 (9,55,0)、(11,30,0); Clock myclock[4]={6,7,8,9}; //4个对象,调带缺省值的构造函数,初值分别为 (6,0,0)、(7,0,0)、(8,0,0)、(9,0,0);
类的调用--const对象 • const说明常量,也可以用它说明对象及对象成员 • 用const说明的对象,称为常对象,其任何数据成员都不能修改; 例如: const Date MyBirthday(3,25,80); • const对象只能调用只读成员函数 • 只读成员函数:只能读取(不可修改)当前对象的成员变量 例如: int GetMonth() const{ return month; } void SetMonth(New_Month){ Month=New_Month; }
类的调用-- const对象 class AA {int a,b; public: AA(int a1,int b1){a=a1;b=b1;} void Show(){ cout<<"1:"<<a<<","<<b<<endl;} void Show() const {cout<<"2:"<<a<<","<<b<<endl;} }; void main() { AA MyA1(10,20); const AA MyA2(40,50); MyA1.Show(); MyA2.Show(); }
3.5 自引用指针this • C++为非静态的成员函数提供了一个名字为this的指针; • 创建一个类的对象时,系统就会自动地把this指针的值初始化为该对象本身; • this指针可以用于当成员函数的形参与数据成员同名时。 例:
自引用指针this 例:class Myclass { int x; int y; public; Myclass(int x,int y) { this—>x = x; this—>y = y; } }; 调用: Myclass b(2,3); 对象b的this指针指向当前对象b本身。
小 结 • 类的定义(属性和方法的定义)及构造函数、析构函数; • 与属性有关的几个知识点:const数据成员、static数据成员和动态数据; • 类的使用:将类看作一个抽象数据类型来用。
思 考 • 1. 比较类的三种继承方式public(公有继承), private(私有继承), protected(保护继承)之间的差别。 • 2.C++中如何实现同一个类不同对象间的数据共享?这种实现方式的定义与全局变量的定义有什么不同?有何好处?
思考 3. 说明构造函数和析构函数的作用。如下对类的调用,请写出相应的构造函数和析构函数。 Class Test { int i,j,k; }; Test t1; Test t2(2,3,4); 4. 写程序运行结果和编程。
课外思考 • C中如何实现字符串的存储和处理? • C++中预定义了string类,它提供了哪些对字符串的处理所需要的操作? • C的运行库与C++标准类库的区别及使用