1.16k likes | 1.29k Views
程序设计实习 第二十二讲 学期小结. 期末考试. A 卷 形式与往年类似 内容以类和对象之后的内容为主 , 前面主要要求枚举和递归的算法思想和链表 B 卷 本学期全部作业题 , 即课程主页上每讲布置的作业. 内容提要. 枚举、递归、链表 C++ 语言综述 类的定义和使用 运算符重载 类的继承 虚函数和多态 输入输出流和文件处理 string 类和字符串处理 类模板和函数模板 STL 标准模板库. 枚举和递归. 两种解题的算法思想 枚举的思想 在解空间枚举所有可能性,逐一判断是否为可行解; 递归的思想
E N D
期末考试 • A卷 • 形式与往年类似 • 内容以类和对象之后的内容为主, 前面主要要求枚举和递归的算法思想和链表 • B卷 • 本学期全部作业题,即课程主页上每讲布置的作业 2
内容提要 • 枚举、递归、链表 • C++语言综述 • 类的定义和使用 • 运算符重载 • 类的继承 • 虚函数和多态 • 输入输出流和文件处理 • string类和字符串处理 • 类模板和函数模板 • STL标准模板库 3
枚举和递归 • 两种解题的算法思想 • 枚举的思想 • 在解空间枚举所有可能性,逐一判断是否为可行解; • 递归的思想 • 将待求解问题的解看作输入变量x的函数f(x),通过寻找函数g,使得f(x) = g(f(x-1)),并且已知f(0)的值,就可以通过f(0)和g求出f(x)的值. • 这样一个思想也可以推广到多个输入变量x,y,z等,x-1也可以推广到 x - x1,只要递归朝着出口的方向走就可以了. 4
链表 • 链表的结构 • 节点由“数据+指针”构成, 所有节点结构相同, 由指针连接在一起 • 链表的特点 • 顺序访问 • 任意位置插入和删除 • 链表的操作:插入、删除算法 • 插入和删除通过改变指针内容完成 • 删除操作对第一个节点和其它节点不同, 所以引入空的头节点, 简化删除操作. • 链表的分类 • 单链表 • 双链表 • 循环链表 5
内容提要 • 枚举、递归、链表 • C++语言综述 • 类的定义和使用 • 类的继承 • 虚函数和多态 • 运算符重载 • 输入输出流和文件处理 • string类和字符串处理 • 类模板和函数模板 • STL标准模板库 6
C++语言综述 • 基本数据及其上的操作(相同类型数据间的操作) • char x,y; +, -, *, /, =; • int x,y; +, - , *, /, %, =, ++, --; • long x,y; +, -, *, /, %, =, ++, --; • __int64 x,y; +, -, *, /, %, =, ++, --; • float x,y; +, -, * , /, =; • double x,y; +, -, *, /, =; 7
C++语言综述 • 用强制类型转换实现不同数据类型变量之间的运算; 例: float x = 3 + 2.5; • 用函数定义不同数据类型之间、不同操作数数目的复杂运算;例:double multiple(int, float, double); • 如果把操作符看作特殊的函数,并将其前置: +(int, int), *(float,float), ++(long) … 则得到一种统一的操作表示: 操作名(操作数1,… ) 8
C++语言综述 • 为了扩展语言的能力,C++提供了类定义的语法机制,可以组合基本的数据类型定义更复杂的数据类型及其上的操作: • 例: class A { public: int x; float y; A & operator+(const A& a1); …… } 9
C++语言综述 • 在定义新的类时可以使用已经定义好的类,并将其看作基本类型来使用,如此的嵌套结构可以定义出任意复杂的类; • 可以用友元函数实现不同类对象之间的操作, • 如此便完成了任意复杂的数据及其上的任意复杂的操作。 10
C++语言综述 • 语言提供的功能并没有到这里就停止: • 与用户交换数据 • C++输入输出流 • 处理数据管理的问题 • C++文件流处理 • 处理异常错误 • C++异常处理 11
C++语言 • 关于代码重用问题 • 类的派生 • 抽象类/虚函数/多态 • 类模板和模板类 • 函数模板和模板函数 • C++类库 12
内容提要 • 枚举、递归、链表 • C++语言综述 • 类的定义和使用 • 运算符重载 • 类的继承 • 虚函数和多态 • 输入输出流和文件处理 • string类和字符串处理 • 类模板和函数模板 • STL标准模板库 13
类的定义和使用 • 定义类的目的 • 类的定义方法 • 类中的主要概念: • 成员变量、成员函数、public、protected、private • 类中的特殊函数:构造函数和析构函数 • 类中的特殊种类成员:引用、对象、常量、静态 • 类的友元 • 用类定义对象:一般对象、常量对象和常量成员函数 • this 指针 14
类的定义和使用 • 定义类的目的 • 定义出一种比较复杂的数据类型来与客观世界中的复杂对象相对应; • 通过类的成员函数定义这种复杂对象上的操作; • 如此便可以把一个复杂对象当作一个整体来处理,是实现抽象,减低问题复杂度的一种方法。 15
类的定义和使用 • 类的定义方法 – 类定义 // man.h class Man { private: int nAge; char szName [20]; public: int GetAge () ; //方法, Method, 也叫成员函数 void SetName( char * szName); //成员函数 }; 16
类的定义和使用 • 类的定义方法 – 定义成员函数 //Man.cpp: #include “man.h” int Man::GetAge(){ return nAge; } void Man::SetName ( char * name) { strcpy( szName,name); } 17
类的定义和使用 • 类中的主要概念: • 成员变量:类中定义的变量 • 成员函数:类中定义的函数 • 访问限定符 • public : 可以在任何地方访问 • protected :在自己内部和子类内部访问 • private : 仅在类定义内访问 18
类的定义和使用 • 类中的特殊函数 • 构造函数 • 析构函数 • 各种构造函数和析构函数的调用时机 19
构造函数(定义) • 构造函数是 public 的; • 无返回值,可以有0到多个参数; • 用户不定义,自动生成缺省的; • 缺省的构造函数什么也不做,没有参数; • 用户定义,则没有缺省的; • 可以定义多个构造函数; • 用于初始化对象的变量; 20
构造函数(调用方式) • 定义对象变量时: Complex c1,c2(2),c3(3,5); • 创建新变量对象时: Complex * pc1 = new Complex ; Complex * pc2 = new Complex(3,4); • 创建数组对象时: Test array1[3] = { 1, Test(1,2) }; Test * pArray[3] = { new Test( 4), new Test(1,2) }; 21
构造函数(复制构造函数) • 特殊构造函数,只有一个参数,类型为本类的引用; • 如果没有定义,生成缺省的复制构造函数; • 如果定义,没有缺省复制构造函数; • 与前面说的构造函数无关; Complex c2(c1); Complex c2 = c1; • 参数传递时,复制参数 • 函数返回时复制返回值 22
转换构造函数 • 带有一个参数的非复制构造函数的构造函数 例: class Complex { public: float real,imag; Complex( double f ) { real = f ; imag = 0; } Complex( int i = 0 ) { real = i; imag = 0; } ~Complex() { printf( "Destructor called\n"); } }; 23
析造函数(定义) • 只有一个; • 没有参数和返回值; • 如果不定义,自动生成,什么也不做; • 如果定义,没有缺省的; • 完成对象消亡前的收尾工作; • ~类名(){ … } 24
析造函数(调用时机) • 变量消亡 • 出作用域 • Delete • 函数返回值用后; 25
各种构造函数和析构函数的调用时机 • 构造函数 • 全局变量: 程序运行前; • main中变量: main开始前; • 函数中静态变量: 函数开始前; • 函数参数:函数开始前; • 函数中变量:函数开始前; • 函数返回值:函数返回前; 26
各种构造函数和析构函数的调用时机 • 析构函数 • 全局变量: 程序结束前; • main中变量: main结束前; • 函数中静态变量: 程序结束前; • 函数参数:函数结束前; • 函数中变量:函数结束前; • 函数返回值:函数返回值被使用后; 27
类的定义和使用 • 类中的特殊种类成员 • const和引用成员 • 对象 • 静态 28
类的定义和使用 • 类中的特殊种类成员 • const和引用成员 • 初始化const 成员和引用成员时,必须在成员初始化列表中进行。 class example { private : const int num; int & ret; int value; public: example( int n,int f) : num(n), ret(f), value(4) { } }; 29
类的定义和使用 • 类中的特殊种类成员 • 对象 例: class Big { private: int n; base1 b1; base2 b2,b3; public: Big (int n ) : b2(n),b3(2) { } }; 30
类的定义和使用 • 类中的特殊种类成员 • 对象 • 有成员是其他类的对象时,本类称为封闭类 • 封闭类对象生成时,先执行所有对象成员的构造函数,然后才执行封闭类的构造函数。 • 对象成员的构造函数调用次序和对象成员在类中的说明次序一致,与它们在成员初始化列表中出现的次序无关。 • 当封闭类的对象消亡时,先执行封闭类的析构函数,然后再执行成员对象的析构函数。次序和构造函数的调用次序相反。 31
类的定义和使用 • 类中的特殊种类成员 • 静态成员 属于整个类而不属于任何类的对象的变量可以定义成静态成员。 例如: class Apple { private : int nWeight; static int nTotalWeight; static int nTotalNumber; public: Apple( int w) ; ~Apple( ) ; static void PrintTotal(); }; • 在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数。 32
类的定义和使用 • 类的友元 • 若想要其它类或函数访问本类的私有成员,可以将其它类或函数说明为自己的友元,此举有利于定义不同类对象间的操作。 例如: class Thing { private: int data; public : friend void SetData( Thing & t, int nValue); friend void B::function(); friend class other; }; 33
类的定义和使用 • 用类定义对象: • 一般对象 • 常量对象和常量成员函数 一般对象,例如: class A{ …… } A a1,a2; 34
类的定义和使用 • 用类定义对象: • 常量对象和常量成员函数 • 如果不希望对象的值被改变,可以将对象定义为常量,例如: const A a1; // a1的值不能改变 通过a1只能访问一类const成员函数,形如: class Sample { private : int value; public: void SetValue() const; //函数中不能改变成员的值 } 35
类的定义和使用 • this 指针 • 在定义某个类的代码中,可以用this指针指代正在定义的类的对象。例如: class Complex { float real,imag; public: Complex * ReturnAddress ( ) { return this; }// c.ReturnAddress 等效于 & c float ReturnReal() { return this -> real;//等效于return real; } Complex operator += ( Complex & c) { real += c.real; imag += c.imag; return * this; }}; 36
内容提要 • 枚举、递归、链表 • C++语言综述 • 类的定义和使用 • 运算符重载 • 类的继承 • 虚函数和多态 • 输入输出流和文件处理 • string类和字符串处理 • 类模板和函数模板 • STL标准模板库 37
运算符重载 • 运算符重载的目的 • 可以对自定义的类的对象使用运算符构建表达式 • 可以重载的运算符 • +、-、*、/、%、^、&、~、!、|、=、<<、>>、!=、…… • 运算符重载的方法 • 说明为成员函数 • 说明为友元函数 38
运算符重载 • 说明为成员函数 -- 鼓励 class CSet { public: CStet(); // constructor const CSet &operator+( const CElement & ) const; …… }; • 说明为友元函数 -- 左操作数不是本类对象 class PhoneNumber { friend ostream &operator<<( ostream&, const PhoneNumber & ); friend istream &operator>>( istream&, PhoneNumber & ); … }; 39
运算符重载 • 流插入运算符的重载,参数和返回值要使用ostream & 类型 ostream & operator<<( ostream & o,const CStudent & s){ o << s.nAge ; return o; } 40
内容提要 • 枚举、递归、链表 • C++语言综述 • 类的定义和使用 • 运算符重载 • 类的继承 • 虚函数和多态 • 输入输出流和文件处理 • string类和字符串处理 • 类模板和函数模板 • STL标准模板库 41
类的继承/派生 • 继承的目的 • 继承的方式:public、protected、private • 派生类的构造函数 • 基类对象指针和派生类对象指针的转换 • 覆盖的概念 42
继承的目的 – 代码重用 • 已经有一个类A,现在要定义的类B和类A很相似,只是多了一些东西,或者说,B是一种特殊的A。 例如: class 学生{ class 学生干部:学生{ public: public: char name[10]; char title[20]; char id[10]; char level; void study(); void duty(); } } 43
类的继承/派生 • 继承的方式:public、protected、private • class derived: public base • public -> public • protected -> protected • private -> private • class derived: protected base • public、protected -> protected • class derived: private base • public、protected -> private 44
类的继承/派生 • 派生类的构造函数 FlyBug::FlyBug ( int legs,int color, int wings) :Bug( legs,color) { nWings = wings; } • 在创建派生类的对象时,需要调用基类的构造函数:初始化派生类对象中从基类继承的成员。在执行一个派生类的构造函数之前,总是先执行基类的构造函数 45
类的继承/派生 • 派生类的构造函数 • 调用基类构造函数的两种方式 • 显式方式:在派生类的构造函数中,为基类的构造函数提供参数 derived::derived(arg_derived-list):base(arg_base-list) • 隐式方式:在派生类的构造函数中,省略基类构造函数时,派生类的构造函数则自动调用基类的默认构造函数 • 派生类的析构函数被执行时,执行完派生类的析构函数后,自动调用基类的析构函数 46
类的继承/派生 • 基类对象指针和派生类对象指针的转换 • 基类指针可以指向子类对象,但用起来就象基类对象 • 将基类指针赋值给子类指针要显式类型转换 例如: class C:public P{…} P *p1 = 0, p( 30, 50 ); C *c1 = 0, c( 2.7, 120, 89 ); p1 = &c; // assign address of c to p1 c1 = static_cast< Circle * >( p1); 47
覆盖的概念 • 基类和子类中的同名函数,在子类中看不到基类的相应函数,这种现象称为覆盖。 48
内容提要 • 枚举、递归、链表 • C++语言综述 • 类的定义和使用 • 运算符重载 • 类的继承 • 虚函数和多态 • 输入输出流和文件处理 • string类和字符串处理 • 类模板和函数模板 • STL标准模板库 49
虚函数和多态 • 引入虚函数的目的 • 虚函数的定义 • 纯虚函数和抽象类 • 在构造函数和析构函数中调用虚函数 • 虚析构函数 50