1 / 37

第五章 类与对象

第五章 类与对象. 类的作用 类界面与类实现 类成员的访问控制 对象的创建. 静态数据成员 构造函数与析构函数 成员对象的初始化. §5.1 面向对象的基本概念和特征. 1. 对象( Object ) 指将数据 ( 内部状态 ) 和使用这些数据的一组基本操作 ( 行为 ) 封装在一起的统一体。 对象有时指一个事物,称 实例 (instance) 有时指一组类似的事物,称 对象类 (class) 2. 信息隐藏 将一个模块的内部数据或操作隐藏起来,其他模块只能通过该模块提供的公开操作来访问该模块 信息隐藏由封装机制来实现。

jaclyn
Download Presentation

第五章 类与对象

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第五章 类与对象 类的作用 类界面与类实现 类成员的访问控制 对象的创建 • 静态数据成员 • 构造函数与析构函数 • 成员对象的初始化

  2. §5.1 面向对象的基本概念和特征 1. 对象(Object) • 指将数据(内部状态)和使用这些数据的一组基本操作(行为)封装在一起的统一体。 • 对象有时指一个事物,称实例(instance)有时指一组类似的事物,称对象类(class) 2. 信息隐藏 • 将一个模块的内部数据或操作隐藏起来,其他模块只能通过该模块提供的公开操作来访问该模块 • 信息隐藏由封装机制来实现。 3.封装: 用两种方法实现

  3. 用两种方法实现封装 (1) 文件模块 • 例子:P129 采用文件模块来封装,实现循环计数器功能 • 此程序共包括2个源程序以及1个头文件 • CIRNUM1.HPP (程序5.1.1 ) 头文件仅包含循环计数器对外公开的函数原型,不涉及内部数据与函数定义; • CIRNUM1.CPP (程序5.1.2 )该源程序是循环计数器的实现文件,以.CPP作为后缀名字,包括了内部数据及函数定义。文件中引用CIRNUM1.HPP :#include "cirnum1.hpp" • CIRDEMO1.CPP (程序5.1.3 )该源程序包括主函数,使用循环计算器

  4. 基类 派生类 (2) 类:用类实现封装 • C++语言通过建立一个合适的循环计数器类,将这些数据与函数结合在一起,形成一个新的数据类型,称为类类型。 4. 类与类的层次结构 • 具有一致数据结构(属性)和行为(操作)的对象可归并为一个类 • 层次结构: • 上层称超类(基类、父类) • 下层称子类(派生类)

  5. 5.类的特征 • 继承性 • 具有层次关系的类的属性和操作进行共享的方式,后代类可以继承祖先类的各种性质 • 多态性 • 同一名字,多种语义;或相同界面,多种实现 • 如:一个函数名代表了多种函数的实现

  6. §5.2 类的定义 一、类的声明 • 类是对一群具有相同属性、表现相同行为的对象的描述 • 类的一般形式 : class 类名 { public: 公有数据和函数 protected: 保护数据和函数 private: 私有数据和函数 }; • 类中定义的数据(变量)称为数据成员 • 类中定义的函数(行为操作)称为成员函数

  7. 例:循环计数器类 class CIRCULAR_NUMBERS { public: void set_mode(int min, int max) // 设置循环计数器的上、下限 { min_val = min; max_val = max; return; } void set_value(int value) // 设置循环计数器的当前值 { current = value; return; } int get_value() //查询循环计数器的当前值 { return current; }

  8. 例:循环计数器类 void increment()// 循环计数器加一 { int mode = max_val – min_val + 1;   current = ((current – min_val) + 1) % mode + min_val; return; } void decrement()// 循环计数器减一 { int mode = max_val – min_val + 1;   current = ((current – min_val) - 1 + mode)% mode + min_val; return; } private: int min_val; // 最小值 int max_val; // 最大值 int current; // 当前值 };

  9. 说明 • 类的数据成员允许是任何数据类型,但不能是本类类型的。正在定义的类名只可以以指针形式声明自己类中的数据成员 class Link class Link { Link member; { Link *member; …… …… }; };

  10. 说明 • 类中的数据成员不允许使用初值表达式 class CIRCULAR_NUMBERS { … private: int min_val =0 ; int max_val =359 ; … }; • 类中的数据成员不允许使用auto、register、 extern修饰,但允许使用static修饰,得到静态数据成员:供该类的所有对象公用

  11. 常数据成员和常成员函数 • const修饰数据成员:用于声明类中的一个常量数据成员。由于类的数据成员在声明时不能有初值表达式,因此类的常量数据成员在声明时不能指定常量值。 class C { const double PI ; …… }; • const修饰成员函数:常量成员函数,常量成员函数中不允许修改本类数据成员的值。 class C { int get_value() const { …… } };

  12. 二、类成员的访问控制 指明成员的可访问性 • 私有段:由private标记的段 段内的数据成员和成员函数称为私有成员,仅能由该类中的成员函数来访问,即仅可在成员函数定义中使用私有成员的名字。 • 公有段:由public标记的段 段内的数据成员和成员函数称为公有成员,为该类提供与外部世界的接口界面,即可在类内也可在类外访问。 • 类中每一个成员都有访问控制属性,若没有明确指明,成员的访问控制方式缺省为private。

  13. 三、类界面与类实现 • 类的成员函数可以在类内定义,也可以在类外定义。 • 类界面:头文件 *.hpp声明类,包括类的所有数据成员,以及成员函数的原型 • 类实现:源程序 *.cpp首先要包含类界面:#include “*.hpp”然后定义成员函数,由于此时成员函数的定义是位于类的外面,因此必须用类名和作用域运算符::来修饰函数名。 • 一般形式为: 成员函数类型 类名::成员函数名(形参表) { 函数体 }

  14. 三、类界面与类实现 例:// 循环计数器加一 class CIRCULAR_NUMBERS {void increment();// 循环计数器加一 void decrement()// 循环计数器减一 { int mode = max_val – min_val + 1;   current = ((current – min_val) - 1 + mode)% mode + min_val; return; } private: int min_val; // 最小值 int max_val; // 最大值 int current; // 当前值 }; void CIRCULAR_NUMBERS :: increment( ) { int mode = max_val - min_val + 1; current = ((current - min_val) + 1) % mode + min_val; return; }

  15. 四、 标识符的类作用域 • { }内即为类作用域 • 在类作用域中声明的标识符只在该类中具有可见性 • 成员名限定:类中一个成员名字可以使用类名和作用域运算符来显式指定 class C void C::set(int val) { public: { value = val; void set(int val); return; private: } int value; }; C::value

  16. §5.3 对象的创建 • 类:数据类型 • 具有类类型的变量称为对象,对象称为类的实例。 int main() { CIRCULAR_NUMBERS angle; // 角度循环计数器 CIRCULAR_NUMBERS month; // 月份循环计数器 angle.set_mode(0, 359); // 设置角度取值范围从0到359 angle.set_value(250); // 设置当前角度为250 month.set_mode(1, 12); // 设置月份取值范围从1到12 month.set_value(11); // 设置当前月为11月 }

  17. CIRCULAR_NUMBER 对象month 对象angle 1 min_val get_value() decrement() increment() set_value() current set_mode() min_val max_val 359 0 250 12 max_val 11 current set_mode() set_mode()代码 set_value() get_value() increment() set_value()代码 increment()代码 decrement() get_value()代码 decrement()代码 §5.3 对象的创建

  18. 一、静态数据成员 • 用static修饰的数据成员:被分配占用一个固定的存储空间,由此类的所有对象共享,对于类来说:静态数据成员相当于类的全局变量。 • 使用方法: • 在类的界面中(定义)声明一个静态数据成员 • 在类实现中,必须再次声明并初始化这个静态数据变量

  19. 一、静态数据成员 // test1.hpp // test1.cppclass C #include “test1.hpp”{ private: int C::s = 18 ; int x, y;static int s; int C::set(int i, int j) public: { x = i ; int set(int,int); y = j ; }; s++; }

  20. set() x y 对象c2 对象c1 x y s: 18 set() set ()代码 一、静态数据成员 // test.cpp #include “test1.hpp” void main( ) { C c1, c2; c1.set(100,200); c2.set(15, 30); } 类C 19 20 100 200 15 30

  21. 二、使用对象成员 • 通过成员选择运算符“.”来访问/使用对象的公有成员 • 对象名.数据成员 • 对象名.成员函数名(实参列表) class C { public: int x,y; void setxy(int a,int b) { x=a; y=b;} }; void main() { int x,y; C: z; z.setxy(3,5); cout<<“x=“<<x<<endl; cout<<“z.x=“<<z.x<<endl; }

  22. §5.4 对象的初始化 一、构造函数 二、析构函数 三、对象成员的初始化

  23. 一、构造函数 • 构造函数是类中的一个特殊函数 • 功能:对该类的对象进行初始化 • 一般形式:类名(形式参数表); • 特点: • 构造函数是公有的,可由用户提供,也可由系统提供缺省的。 • 构造函数可以有任何类型的形参,但是无返回值,也不能指定返回类型。 • 构造函数在声明一个新对象时调用(对象声明语句中为构造函数提供实参),不可显式调用

  24. 例: class CIRCULAR_NUMBERS { private: int max, min, value; public: CIRCULAR_NUMBERS(int min, int max, int value); // 设置循环计数器的上下限和当前值 …… }; 程序5.4.2 … // 设置循环计数器的上下限和当前值 CIRCULAR_NUMBERS::CIRCULAR_NUMBERS(int min, int max, int value) { min_val = (min <= max) ? min : max; max_val = (min <= max) ? max : min; if (value < min_val) current = min_val; else { if (value > max_val) current = max_val; else current = value; } return; } ……

  25. …… int main() { // 创建两个循环计数器对象并初始化 CIRCULAR_NUMBERS angle(0, 359, 250); // 角度循环计数器 CIRCULAR_NUMBERS month(1, 12, 11); // 月份循环计数器 …… }

  26. 二、析构函数 • 析构函数也类中的一个特殊函数 • 功能:为撤销一个类的对象做善后清理工作(如:回收对象所占用存储空间) • 一般形式:~类名( ); • 特点: • 析构函数是公有的,可由用户提供,也可由系统提供缺省的。 • 析构函数不可带任何参数,无返回值,也不能指定返回类型。 • 在对象生存期结束时,程序将自动调用该对象所属类的析构函数,调用且仅调用一次。

  27. 运行结果是: Initial value is 30 This is the end of main(). Goodbye! 例: #include <iostream.h>  class DEMO_CLASS { public: DEMO_CLASS(int i); ~DEMO_CLASS(); }; DEMO_CLASS::DEMO_CLASS(int i) { cout << "Initial value is " << i << "\n"; return; }  DEMO_CLASS::~DEMO_CLASS() { cout << "Goodbye!\n"; return; }  int main() { DEMO_CLASS obj(30);// 声明一个对象 cout << "This is the end of main().\n"; return 0; }

  28. 三、对象成员的初始化 • 对象成员:在一个类中声明具有类类型的数据成员 • 初始化对象成员的方法:在本类的构造函数中调用这些对象成员所属类的构造函数,其一般形式:类名::类名(形参表):初始化列表{ …… } class A …… { public: B::B():obj2(10,20), obj1(5,3) A(int a, float b); { …… }; } class B { A obj1, obj2; public: B(); }

  29. 说明 • 如果有多个对象成员,对象成员构造函数的调用次序取决于这些成员在类中声明的次序。 • 执行次序: • 创建类的对象时,调用此类的构造函数,先根据初始化列表调用对象成员的构造函数,初始化对象成员,然后才执行本身的构造函数的函数体。 • 析构函数调用的次序正好相反。

  30. 类中包含有另一个类的对象的例子 //在构造函数和析构函数中加入输出以便跟踪 #include<iostream.h> class Object { int val; public: Object( ); //构造函数 Object( int i ); //构造函数 ~Object( ); //析构函数 }; Object::Object( ) { val=0; cout<<"\n Default constructor for Object.\n"; }

  31. Object::Object( int i) //构造函数定义 { val=i; cout<<"\n Constructor for Object: "<<val<<endl; } Object::~Object( ) //析构函数定义 { cout<<"\n Destructor for Object: "<<val<<endl;} class Container //定义新类,它含Object的对象 { private: int date; Object one; //对象成员 Object two; //对象成员 public: Container( ); //构造函数 Container( int i, int j, int k); //构造函数 ~Container( ); //析构函数 };

  32. Container::Container( ) //构造函数定义 { date=0; cout<<"\n Default constructor for Container.\n"; } Container::Container( int i, int j, int k):two(i),one(j) { date=k; cout<<"\n Constructor for Container.\n"; } Container::~Container( ) { cout<<"\n Destructor for Container.\n"; } void main( ) //演示程序 { cout<<"\n... Entering main ...\n"; Container obj(5,6,10); cout<<"\n... Exiting main ...\n"; }

  33. 执行结果为: ... Entering main ... Constructor for Object: 6 //对象one调用构造函数 Constructor for Object: 5 //对象two调用构造函数 Constructor for Container. //调用Container的构造函数 ...Exiting main ... Destructor for Container. //调用Container的析构函数 Destructor for Object: 5 //调用two的析构函数 Destructor for Object: 6 //调用one的析构函数

  34. 初始化列表的其他用途 • 基本数据类型的数据成员也可用初始化列表做初始化 class C { public: C(int i):number(i) <=>C(int i) {……}{ number = i; private: …… int number;} };

  35. 常量数据成员的初始化 常量数据成员: 不能在类的声明中初始化(类中不能用初值表达式) 不能在构造函数中设置其值(赋值操作不能用于常量) 只能采用初始化列表中来赋值 例:class C C::C(int i): PI(3.14159) { public: { C(int i); …… private: } const double PI ; };

  36. 例: #include <iostream.h> #include <conio.h> class base { public: base(char *s) { cout<<"Construct for Base "<<s<<"\n"; } ~base() { cout<<"Destruct for Base\n"; } }; class screen { private: const unsigned size; long price; base obj; public: screen(int s, long p):size(s),price(p),obj("testing") {cout<<"Construct for Screen\n"; } void list(); ~screen() { cout<<"Destruct for Screen\n"; } };

  37. void main() { screen nec(14,40000L); nec.list(); getch(); } void screen::list() { cout<<"The size of the screen is :"<<size<<"\n"; cout<<"The price of the screen is :"<<price<<"\n"; } 运行结果: Construct for Base testing Construct for Screen The size of the screen is :14 The price of the screen is :40000 Destruct for Screen Destruct for Base

More Related