程序设计实习
Download
1 / 116

程序设计实习 第二十二讲 学期小结 - PowerPoint PPT Presentation


  • 151 Views
  • Uploaded on

程序设计实习 第二十二讲 学期小结. 期末考试. Blokus 需要报告 所有作业在 28 日晚 24 点前提交 29 日下午考试 , 各同学所在的教室见课程网站 可以带一张 A4 纸 , 上面可以记录任何内容 . 必须有自己姓名和学号 A 卷 : 内容以类和对象之后的内容为主 , 前面主要要求枚举和递归的算法思想和链表 单项概念选择题 : 20 看程序写结果 : 30 看结果补充程序代码 : 30 写程序代码 :20 B 卷 本学期全部作业题 , 即课程主页上每讲布置的作业. 内容提要. 枚举、递归、链表 C++ 语言综述 类的定义和使用

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' 程序设计实习 第二十二讲 学期小结' - tasya


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.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

程序设计实习第二十二讲 学期小结


期末考试

  • Blokus需要报告

  • 所有作业在28日晚24点前提交

  • 29日下午考试, 各同学所在的教室见课程网站

  • 可以带一张A4纸, 上面可以记录任何内容. 必须有自己姓名和学号

  • A卷:内容以类和对象之后的内容为主, 前面主要要求枚举和递归的算法思想和链表

    • 单项概念选择题: 20

    • 看程序写结果: 30

    • 看结果补充程序代码: 30

    • 写程序代码:20

  • 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


虚函数和多态

  • 引入虚函数的目的

    • 在基类中定义了一种操作,这一操作在各个子类中有不同的表现,此时可以把基类中的函数声明为虚函数,当用基类指针指向不同的子类对象时,调用该函数,可以使它有不同的表现。

    • 如此做法就好比在基类开了一个洞,可以透过虚函数,从基类访问子类的成员函数。进而使在基类处的同一个操作,可以有不同表现,这一现象称为多态。

51


虚函数和多态

  • 虚函数的定义

    class base {

    virtual int get() ;

    }

    int base::get() {

    }

  • 从base 向下的子类中的get()函数,都是虚函数。

52


虚函数和多态

  • 纯虚函数和抽象类

  • 纯虚函数是没有任何实现的虚函数,其写法如下:

    class A {

    private: int a;

    public:

    virtual void Print( ) = 0 ; //纯虚函数

    void fun() { cout << “fun”; }

    };

    区别于空虚函数virtual void Print( ){};

53


虚函数和多态

  • 纯虚函数和抽象类

  • 包含纯虚函数的类是抽象类。抽象类不能有对象,仅作为其它类的基类实用。

54


虚函数和多态

  • 抽象类的用途

    • 有几个类有一些共性的地方,为了不重写它们共同的代码,做一个抽象类,把他们的共同点写出来,而把貌似相同而实质不同的地方用虚函数描述一致的接口,把根本不同的东西放在各自的类定义里。

    • 例:工人、农民、教师、医生等都是劳动者

55


虚函数和多态

class 劳动者{

public:

char 姓名[10];

int 年龄;

bool 性别;

float 工资;

virtual double 劳动() = 0;

}

56


虚函数和多态

class 工人:劳动者{

public:

char 安全帽[10];

double 劳动(){在工厂干活};

}

class 农民:劳动者{

public:

char 农具[10];

double 劳动(){种地};

}

57


虚函数和多态

class 教师:劳动者{

public:

char 教科书[20];

double 劳动(){教书};

}

class 医生:劳动者{

public:

char 医疗器械[50];

double 劳动(){看病};

}

58


虚函数和多态

  • 在构造函数和析构函数中调用虚函数

    • 在构造函数和析构函数中调用虚函数时,采用静态联编,即:他们调用的函数是自己的类或基类中定义的函数,不会等到运行时才决定调用自己的还是派生类的函数。

    • 在普通成员函数中调用虚函数,采用动态联编的方式。

59


虚函数和多态

  • 虚析构函数

    • 通过基类的指针删除派生类对象时,通常情况下只调用基类的析构函数

      • 但是,删除一个派生类的对象时,应该先调用派生类的析构函数,然后调用基类的析构函数

    • 解决办法:把基类的析构函数声明为virtual

      • 派生类的析构函数可以virtual不进行声明

      • 通过基类的指针删除派生类对象时,首先调用派生类的析构函数,然后调用基类的析构函数

    • 一般来说,一个类如果定义了虚函数,则应该将析构函数也定义成虚函数。

    • 注意:不允许以虚函数作为构造函数

60


内容提要

  • 枚举、递归、链表

  • C++语言综述

  • 类的定义和使用

  • 运算符重载

  • 类的继承

  • 虚函数和多态

  • 输入输出流和文件处理

  • string类和字符串处理

  • 类模板和函数模板

  • STL标准模板库

61


输入输出流和文件处理

  • 流的概念

  • 输入输出流及其上的操作

  • 文件流及其上的操作

62


流的概念模型

  • 流 - 可以看作一个无限长的二进制数字序列

  • 通过读写指针进行流的读和写(以字节为单位)

将流上的数据读进变量x

将y的值写入流

x

y

63


流的概念模型

  • 输出流

  • 可以看作一端无限,另一端通过写指针不停地向后写入新内容的单向流,

~

写指针

64


流的概念模型

  • 输入流

  • 可以看作一端无限,另一端通过读指针不停地从流中读取新内容的单向流,读出的内容从流中删去。

~

读指针

65


C++中与流操作相关的类及其继承关系

ios

ostream

istream

iostream

ofstream

ifstream

fstream

66


标准流对象

  • 输入流对象: cin 与标准输入设备相连

  • 输出流对象:cout 与标准输出设备相连

    cerr 与标准错误输出设备相连

    非缓冲输出

    clog 与标准错误输出设备相连

    缓冲输出

  • 向输出流中写数据时,通常是先向缓冲区中写,当缓冲区写满时,才真正向输出流写;也可以通过函数在程序中主动将缓冲区内容写入输出流。

67


输出流输入流

  • 流插入运算符 <<

    • cout.put(‘A’)

  • 读取运算符 >>

    • cin.get()

    • cin.get(char *buffer, int size,char delim=‘\n’ )

    • cin.getline(char *buffer, int size,char delim=‘\n’)

    • cin.eof()

    • cin.peek()

    • cin.putback(ch)

    • cin.ignore(int nCount = 1, int delim = EOF )

68


无格式输入输出

  • 用read, write 进行指定字节数的输入输出

    const int SIZE = 80;

    char buffer[SIZE];

    cin.read(buffer, 20);

    cout.write(buffer, cin.gcount());

    //gcount返回上次读入的字节数

    cout << endl;

    输入:Using the read, write and gcount member functions

    输出:Using the read, write

69


流操纵算子

  • 整数流的基数:流操纵算子dec,oct,hex,setbase

  • 浮点数的精度(precision,setprecision)

  • 设置域宽(setw,width)

  • 用户自定义的流操纵算子

    ostream &tab(ostream &output){

    return output << ‘\t’;

    }

    cout << “aa” << tab << “bb” << endl;

70


文件操作

  • 数据的层次

  • 文件和流

  • 文件的建立

  • 文件的打开

  • 文件的读写

  • 文件的关闭

71


数据的层次

  • 位 bit

  • 字节 byte

  • 域/记录

    例如:学生记录

    int ID;

    char name[10];

    int age;

    int rank[10];

  • 我们将所有记录顺序地写入一个文件,称为顺序文件。

72


文件和流

  • 可以将顺序文件看作一个有限字符构成的顺序字符流,然后象对cin, cout 一样的读写。回顾一下输入输出流类的结构层次:

ios

ostream

istream

iostream

ofstream

ifstream

fstream

73


文件的建立

  • #include <fstream.h> // 包含头文件

    ofstream();

    ofstream( const char* szName, int nMode = ios::out, int nProt = filebuf::openprot );

    ifstream();

    ifstream( const char* szName, int nMode = ios::in, int nProt = filebuf::openprot );

74


文件的打开

  • void open( const char* szName, int nMode, int nProt = filebuf::openprot );

  • nMode

    • ios::app

    • ios::ate

    • ios::in

    • ios::out

    • ios::trunc

    • ios::nocreate

    • ios::noreplace

    • ios::binary

  • nProt

  • filebuf::sh_compat

    • Compatibility share mode (MS-DOS only).

  • filebuf::sh_none

    • Exclusive mode — no sharing.

  • filebuf::sh_read

    • Read sharing allowed.

  • filebuf::sh_write

    • Write sharing allowed.

75


文件的读写指针

  • 对于输入文件,有一个读指针;

  • 对于输出文件,有一个写指针;

  • 对于输入输出文件,有一个读写指针;

  • 标识文件操作的当前位置, 该指针在哪里,读写操作就在哪里进行。

76


文件的读写指针

ofstream fout(“a1.out”,ios::ate);

long location = fout.tellp();

//取得写指针的位置

location = 10L;

fout.seekp(location);

// 将写指针移动到第10个字节处

fout.seekp(location,ios::beg); //从头数location

fout.seekp(location,ios::cur); //从当前位置数location

fout.seekp(location,ios::end); //从尾部数location

location 可以为负值

77


文件的读写指针

ifstream fin(“a1.in”,ios::ate);

long location = fin.tellg();

//取得读指针的位置

location = 10L;

fin.seekg(location);

// 将读指针移动到第10个字节处

fin.seekg(location,ios::beg); //从头数location

fin.seekg(location,ios::cur); //从当前位置数location

fin.seekg(location,ios::end); //从尾部数location

location 可以为负值

78


有格式读写

int x, y; // 有类型的读写

fin >> x >> y;

fout << x << “ “ << y << endl;

  • 说明:

    • 有类型的读写本质是将所有类型转为字符串,再将字符串转成各种类型的数据。

    • 所以写出来的是文本格式的文件。可以在记事本中阅读。

    • 因为文件流也是流,所以前面讲过的流的成员函数和流操作算子也同样适用于文件流。

79


无格式读写

int x=10;

fout.seekp(20, ios::beg);

fout.write(reinterpret_cast<const char *>(&x),sizeof(int));

fin.seekg(0, ios::beg);

fin.read(reinterpret_cast<char *>(&x),sizeof(int));

  • 无格式读写,直接写二进制数据,记事本看未必正确。

80


显式关闭文件

ifstream fin(“test.dat”,ios::in);

fin.close();

ofstream fout(“test.dat”,ios::out);

fout.close();

81


内容提要

  • 枚举、递归、链表

  • C++语言综述

  • 类的定义和使用

  • 运算符重载

  • 类的继承

  • 虚函数和多态

  • 输入输出流和文件处理

  • string类和字符串处理

  • 类模板和函数模板

  • STL标准模板库

82


String
string类和字符串处理

  • string 的定义和使用

  • string的赋值与连接

  • 比较string

  • 子串、交换和特性

  • 在string中寻找、替换和插入字符

  • 字符串流处理

83


String1
string 的定义与使用

  • string 类 是一个模板类 ,它的定义如下:

    typedef basic_string<char> string;

  • 使用string类要包含头文件 <string.h>

  • string对象的初始化:

    • string s1("Hello"); // 一个参数的构造函数

    • string s2(8,’x’); // 两个参数的构造函数

    • string month = “March”; // 复制构造函数

84


String2
string 的赋值与连接

string s1("catdog"), s2, s3;

s2 = s1;

s3.assign(s1);

s3.assign(s1, 1, 3);

s2[5] = s1[3] = ‘a’;

cout << s1.at(5) << endl; // 检查范围

string s1("good "), s2("morning! ");

s1 += s2;

s1.append(s2);

s2.append(s1, 3, s1.size());

85


String3
string的比较

  • 用关系运算符比较string的大小

    • == , >, >=, <, <=, !=

    • 返回值都是bool类型,成立返回true, 否则返回false

  • 用成员函数compare比较string的大小

    string s1("hello"),s2("hello"),s3("hell");

    int f1 = s1.compare(s2);

    int f3 = s3.compare(s1);

    int f4 = s1.compare(1,2,s3,0,3); //s1 1-3; s3 0-3

86


子串、交换、特性

string s1("hello world"), s2;

s2 = s1.substr(4,5); // 下标4开始5个字符

s1.swap(s2);

capacity()

maximum_size()

length()

size()

empty()

resize()

87


String4
string中查找

string s1("hello worlld");

cout << s1.find("ll") << endl;

cout << s1.find("abc") << endl;

cout << s1.rfind("ll") << endl;

cout << s1.rfind("abc") << endl;

cout << s1.find_first_of("abcde") << endl;

cout << s1.find_first_of("abc") << endl;

cout << s1.find_last_of("abcde") << endl;

cout << s1.find_last_of("abc") << endl;

cout << s1.find_first_not_of("abcde") << endl;

cout << s1.find_first_not_of("hello world") << endl;

cout << s1.find_last_not_of("abcde") << endl;

cout << s1.find_last_not_of("hello world") << endl;

88


String5
string 中删除、替换、插入

string s1("hello worlld");

s1.erase(5); //删除5及其后的字符

s1.replace(2,3, “haha");

s1.replace(2,3, "haha", 1,2);

string s1("hello world");

string s2(“show insert");

s1.insert(5,s2); // 将s2插入s1下标5的位置

s1.insert(2,s2,5,3);

89


字符串流处理

  • 除了标准流和文件流输入输出外,还可以从string进行输入输出;

  • 类似 istream和osteram进行标准流输入输出,我们用 istringstream 和 ostringstream进行字符串上的输入输出,也称为内存输入输出。

  • #include <string.h>

  • #include <iostream>

  • #include <sstream>

90


字符串流处理

  • 例:字符串输入流

    string input("Input test 123 4.7 A");

    istringstream inputString(input);

    string string1, string2;

    int i;

    double d;

    char c;

    inputString >> string1 >> string2 >> i >> d >> c;

    cout << string1 << endl << string2 << endl;

    cout << i << endl << d << endl << c <<endl;

    long l;

    if(inputString >> l) cout << "long\n";

    else cout << "empty\n";

91


内容提要

  • 枚举、递归、链表

  • C++语言综述

  • 类的定义和使用

  • 运算符重载

  • 类的继承

  • 虚函数和多态

  • 输入输出流和文件处理

  • string类和字符串处理

  • 类模板和函数模板

  • STL标准模板库

92


类模板

问题的提出

类模板的定义

模板类的概念

类模板的使用

函数模板

问题的提出

模板函数的概念

函数模板的定义

函数模板的使用

类模板和函数模板

93


类模板

  • 问题的提出

  • 类模板的定义

  • 模板类的概念

  • 定义类模板的成员函数

  • 使用类模板声明对象

94


类模板 – 问题的提出

  • 为了多快好省地定义出一批相似的类,可以定义类模板,然后由类模板生成不同的类.

  • 考虑一个数组类,需要提供的基本操作

    • Len():查看数组的长度

    • getElement(int index):获取其中的一个元素

    • setElement(int index):对其中的一个元素进行赋值

    • ……

  • 数组是一种常见的数据类型,元素可以是:

    • 整数

    • 学生

    • 字符串

    • ……

95


类模板– 问题的提出

  • 这些数组类,除了元素的类型不同之外,其他的完全相同;

  • 类模板:在定义类的时候给它一个/多个参数,这个/些参数表示不同的数据类型。在调用类模板时,指定参数,由编译系统根据参数提供的数据类型自动产生相应的模板类

96


类模板的定义

template <class T>//类模板的首部,声明类模板的参数

class Carray{

T *ptrElement;

int size;

public:

Carray(int length);

~Carray();

int len();

void setElement(T arg, int index);

T getElement(index);

}

  • template:

    • Carray是一个类模板

    • 声明一个、或多个类型参数,用来定义Carray的属性类型、成员服务的参数类型和返回值类型

97


模板类的概念

  • 模板类:为类模板中各类型参数指定了具体的数据类型后,即得到一个模板类。

    • 编译系统自动用具体的数据类型替换类模板中的类型参数,生成模板类的代码

    • 为类型参数指定的数据类型不同,得到的模板类不同

98


定义类模板的成员函数

  • 定义类模板的成员函数

    template <class T>// T是模板类Carray<T>的类型参数

    Carray<T>::Carray(int length){//模板类Carray<T>的构造函数

    ptrElement = new T[length];

    size = length;

    }

    template <class T> // T是模板类Carray<T>的类型参数

    Carray<T>::~ Carray(){//模板类Carray<T>的析构函数

    Delete [] ptrElement;

    }

99


定义类模板的成员函数

template <class T> // T是模板类Carray<T>的类型参数

int Carray<T>::len(){//模板类Carray<T>的成员服务len()

return size;

}

template <class T> // T是模板类Carray<T>的类型参数

void Carray<T>:: setElement(T arg, int index) {

//模板类Carray<T>的成员服务setElement(T arg, int index)

*(ptr+index) = arg;

return;

}

template <class T> // T是模板类Carray<T>的类型参数

T Carray<T>:: getElement(T arg, int index) {

//模板类Carray<T>的成员服务getElement(T arg, int index)

return *(ptr+index);

}

100


使用类模板声明对象

Carray<int> arrayInt(50), *ptrArrayInt;

//创建一个元素类型为int的Carray模板类,并声明该模板类的一个对象、以及一个指针

Carray<string> arrayStr(100);

//创建一个元素类型为string的Carray模板类,并声明该模板类的一个对象,其中string是C++标准类库中的字符串类

Carray<CStudent> *ptrArrayStudent;

//创建一个元素类型为CStudent的Carray模板类,并声明该模板类的一个指针,其中CStudent是程序员自定义的一个类

101


使用类模板声明对象

  • 同一个类模板的两个模板类是不兼容的

    • ptrArrayInt = & arrayInt; //ok

    • ptrArrayInt = & arrayStr; //error

102


函数模板的提出

  • 为了描述一类公共的计算过程,不论数据的类型怎样,该计算过程都可以工作。

103


函数模板和模板函数

  • 编写一个函数模板,由编译系统根据函数调用的实参类型自动产生模板函数

    • 根据函数调用的参数,匹配最合适的函数(包括普通函数、已经创建的模板函数)

    • 如果匹配不成功,找到函数模板,根据实参的类型,创建一个合适的模板函数

  • 由同一个函数模板产生的不同模板函数之间是函数重载关系

104


定义函数模板

template <class T>

T sum( T a, T b){

if(a>b) return 0;

return a.current() + sum(a.next(), b) ;

}

105


使用函数模板

void main(){

A a(1), b(10); //省略ABC的定义

B c(1), d(3);

C e(1), f(3);

cout << sum(a,b) << endl;

cout << sum(c,d) << endl;

cout << sum(e,f) << endl;

}

输出:

55

36

6 0.372006

106


内容提要

  • 枚举、递归、链表

  • C++语言综述

  • 类的定义和使用

  • 类的继承

  • 虚函数和多态

  • 运算符重载

  • 输入输出流和文件处理

  • string类和字符串处理

  • 类模板和函数模板

  • STL标准模板库

107


STL标准模板库

  • 基本概念

    • 容器

    • 迭代器

    • 算法

  • 类模板

    • 容器的分类:顺序容器、关联容器、容器适配器

    • 容器的成员函数

    • 迭代器

  • 函数模板

108


STL中的基本概念

  • 容器:可容纳各种数据类型的数据结构。

  • 迭代器:可依次存取容器中元素的东西。

  • 算法:用来操作容器中的元素的函数模板。例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象。函数本身与他们操作的数据的结构和类型无关,因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用。

109


容器的分类

  • 1) 顺序容器  

    • vector, deque,list

  •  2)关联容器

    • set, multiset, map, multimap

  • 前2者合称为第一类容器

  • 3)容器适配器

    • stack, queue, priority_queue

110


容器的成员函数

  • 1)所有标准库容器共有的成员函数:

    • 比较两个容器的运算符: =, < , <= , > , >=, == , !=

    • empty : 判断容器中是否有元素

    • max_size: 容器中最多能装多少元素

    • size: 容器中元素个数

    • swap: 交换两个容器的内容

111


容器的成员函数

  • 2) 只在第一类容器中的函数:

    • begin 返回指向容器中第一个元素的迭代器

    • end 返回指向容器中最后一个元素后面的位置的迭代器

    • rbegin 返回指向容器中最后一个元素的迭代器

    • rend 返回指向容器中第一个元素前面的位置的迭代器

    • erase 从容器中删除一个或几个元素

    • clear 从容器中删除所有元素

112


迭代器

  • STL 中的迭代器按功能由弱到强分为5种:

    • 1. 输入:Input iterators 提供对数据的只读访问。

    • 1. 输出:Output iterators 提供对数据的只写访问

    • 2. 正向:Forward iterators 提供读写操作,并能一次一个地向前推进迭代器。

    • 3. 双向:Bidirectional iterators提供读写操作,并能一次一个地向前和向后移动。

    • 4. 随机访问:Random access iterators提供读写操作,并能在数据中随机移动。

    • 编号大的迭代器拥有编号小的迭代器的所有功能,能当作编号小的迭代器使用。

113


迭代器

  • 不同迭代器所能进行的操作(功能):

    • 所有迭代器: ++p, p ++

    • 输入迭代器: * p, p = p1, p == p1 , p!= p1

    • 输出迭代器: * p, p = p1

    • 正向迭代器: 上面全部

    • 双向迭代器: 上面全部,--p, p --,

    • 随机访问迭代器: 上面全部,以及:

      p+= i, p -= i,

      p + i: 返回指向 p 后面的第i个元素的迭代器

      p - i: 返回指向 p 前面的第i个元素的迭代器

      p[i]: p 后面的第i个元素的引用

      p < p1, p <= p1, p > p1, p>= p1

114


迭代器

容器 迭代器类别

vector 随机

list 双向

set/multiset 双向

map/multimap 双向

115


算法

  • 数学方法:random_shuffle、count、count_if、min_element、max_element、accumulate、for_each、

    transform

  • 查找:find、find_if、binary_search、lower_bound、uper_bound、equal_range

  • 排序:sort

116


ad