第八章 多态性和虚函数 胡昊 南京大学计算机系软件所.

Slides:



Advertisements
Similar presentations
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构.
Advertisements

面向对象程序设计 QQ群: Object-Oriented Programming 汽车学院.
程序设计实习 3月份练习解答
第一章 C语言概述 计算机公共教学部.
第5章 指 针 教学目标: 掌握指针定义、初始化方法和基本运算; 掌握利用指针访问一维数组、二维数组的方法;
第4章 数组 数组是由一定数目的同类元素顺序排列而成的结构类型数据 一个数组在内存占有一片连续的存储区域 数组名是存储空间的首地址
第14章 c++中的代码重用.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
C++程序设计 王希 图书馆三楼办公室.
Using C++ The Weird Way Something about c++11 & OOP tricks
第5章 函数与模块化设计 学习目的与要求: 掌握函数的定义及调用方法 理解并掌握参数的传递方法 理解函数的嵌套与递归调用
函數(一) 自訂函數、遞迴函數 綠園.
第4章 函数与预处理 4.1 概述 4.2 定义函数的一般形式 4.3 函数参数和函数的值 4.4 函数的调用 *4.5 内置函数
教材 《C++程序设计》.谭浩强. 清华大学出版社 王雪晶
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
第五章 模 板.
Chapter 14 Templates.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Object-Oriented Programming in C++ 第一章 C++的初步知识
程序设计期末复习 黎金宁
第三章 C++中的C 面向对象程序设计(C++).
第12章 從C到C++語言 12-1 C++語言的基礎 12-2 C++語言的輸出與輸入 12-3 C++語言的動態記憶體配置
辅导课程六.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
第六章 数据抽象-类 胡昊 南京大学计算机系软件所.
C++语言程序设计 第二章 C++简单程序设计.
泛型委托 泛型接口、方法和委托.
程序的三种基本结构 if条件分支语句 switch多路开关语句 循环语句 循环嵌套 break,continue和goto语句
谭浩强 编著 中国高等院校计算机基础教育课程体系规划教材 C++程序设计.
第十章 模板 丘志杰 电子科技大学 计算机学院 软件学院.
第七章 操作符重载 胡昊 南京大学计算机系软件所.
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
常宝宝 北京大学计算机科学与技术系 数据结构(三) 常宝宝 北京大学计算机科学与技术系
C语言程序设计 主讲教师:陆幼利.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
C++语言程序设计 C++语言程序设计 第五章 函数 第十一组 C++语言程序设计.
C语言大学实用教程 第5章 函数与程序结构 西南财经大学经济信息工程学院 刘家芬
$9 泛型基础.
潘爱民 C++ Overview 潘爱民
C++语言程序设计 C++语言程序设计 第三章 控制语句 第十一组 C++语言程序设计.
第二章 Java基本语法 讲师:复凡.
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
第五章 函 数 要点:掌握函数的定义,函数的原形,函数的返回值,函数的调用,函数的形式参数和实际参数之间的关系;掌握函数重载的使用方法,关键字inline的含义与使用,掌握变量的作用域与生存期,了解函数的作用域。
C程序设计.
本节内容 类成员的访问控制 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C语言程序设计 李祥 QQ:
C++语言程序设计教程 第2章 数据类型与表达式 第2章 数据类型与表达式 制作人:杨进才 沈显君.
C qsort.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
第二章 类型、对象、运算符和表达式.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
辅导课程十五.
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
#include <iostream.h>
第四章 函数 丘志杰 电子科技大学 计算机学院 软件学院.
第7章 模板 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
C++程序语言设计 Chapter 14: Templates.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
Presentation transcript:

第八章 多态性和虚函数 胡昊 南京大学计算机系软件所

重要内容 类属(泛型)的基本概念 函数模板 类模板 模板的复用 C++标准模板库简介

类属(泛型)程序设计 在程序设计中经常需要用到一些功能完全相同的程序实体,但它们所涉及的数据的类型不同。 例如,对不同元素类型的数组进行排序的函数: void int_sort(int x[],int num); void double_sort(double x[],int num); void A_sort(A x[],int num); 这三个函数的实现基本是一样的。

再例如,元素类型不同的栈类 class AStack class IntStack { A buf[100]; public: bool push(A); bool pop(A&); }; class IntStack { int buf[100]; public: bool push(int); bool pop(int&); }; class DoubleStack { double buf[100]; public: bool push(double); bool pop(double&); }; 这三个类的实现基本也是一样的。

类属(泛型)程序设计(续) 对于前面的三个排序函数和三个类,如果能分别只用一个函数和一个类来描述它们将会大大简化程序设计的工作。 在程序设计中,一个程序实体能对多种类型的数据进行操作或描述的特性称为类属性。 基于具有类属性的程序实体进行程序设计的技术称为:类属程序设计(或泛型程序设计,Generic Programming)。 具有类属性的程序实体通常有: 类属函数 类属类

类属函数 类属函数是指一个函数能对不同类型的参数完成相同的操作。 C++提供了下面两种实现类属函数的机制: 通过指针类型参数的函数 通过函数模板

指针参数实现类属函数 void sort(void *base, //需排序的数据首地址 unsigned int count, //数据元素的个数 unsigned int element_size, //数据元素的尺寸 int (*cmp)(const void *, const void *) ) //比较两个元素的函数 { /* 不论采用何种排序算法,一般都需要对数组进行以下操作: 1、取第i个元素 (char *)base+i*element_size 2、比较第i个和第j个元素的大小 (*cmp)((char *)base+i*element_size, (char *)base+j*element_size) 3、交换第i个和第j个元素 char *p1=(char *)base+i*element_size, *p2=(char *)base+j*element_size; for (int k=0; k<element_size; k++) { char temp=p1[k]; p1[k] = p2[k]; p2[k] = temp; } */ }

int int_compare(const void *p1, const void *p2) { if (*(int *)p1 < *(int *)p2) return –1; else if (*(int *)p1 > *(int *)p2) return 1; else return 0; } int double_compare(const void *p1, const void *p2) //比较double类型元素大小。 { if (*(double *)p1 < *(double *)p2) else if (*(double *)p1 > *(double *)p2)

int A_compare(const void *p1, const void *p2) { if (*(A *)p1 < *(A *)p2) //类A需重载操作符:< return –1; else if (*(A *)p1 > *(A *)p2) //类A需重载操作符:> return 1; else return 0; } ...... int a[100]; sort(a,100,sizeof(int),int_compare); double b[200]; sort(b,200,sizeof(double),double_compare); A c[300]; sort(c,300,sizeof(A),A_compare);

冒泡排序算法 输入n个数给a[1]到a[n] for j=1 to n-1 for i=1 to n-j a[i] > a[i+1] 真 假 a[i]  a[i+1] 输出a[1]到a[n]

冒泡排序程序 #include <iostream.h> void main() { int a[11]; int i, j, t; cout<<“input 10 numbers:”<<endl; for(i=1; i<11; i++) cin>>a[i]; cout<<endl; for(j=1; j<=9; j++) for(i=1; i<=10-i; i++) if(a[i]>a[i+1]) { t=a[i]; a[i]=a[i+1]; a[i+1]=t; } cout<<“The sorted numbers”<<endl; cout<<a[i]; }

函数模板 在C++中,实现类属函数的另外一种办法是用函数模板。函数模板是指带有类型参数的函数定义,其格式如下: template <class T1, class T2, ...> <返回值类型> <函数名>(<参数表>) { ...... } 其中, T1、T2等是函数模板的类型参数 <参数表>中的参数类型以及函数体中的局部变量的类型可以是:T1、T2等 使用函数模板定义的函数时需要提供与T1、T2相对应的具体类型。

例如: template <class T> void sort(T elements[], unsigned int count) { /* 1、取第i个元素 elements[i] 2、比较第i个和第j个元素的大小 elements[i] < elements [j] 3、交换第i个和第j个元素 T temp=elements [i]; elements[i] = elements [j]; elements[j] = temp; */ }

除了类型参数外,函数模板也可以带有非类型参数。 例如: template <class T, int size> //size为一个int型的普通参数。 void f(T a) { T temp[size]; ...... }

函数模板的使用 函数模板定义了一系列重载的函数。要使用函数模板所定义的函数(称为模板函数),首先必须要对函数模板进行实例化(生成具体的函数)。函数模板的实例化通常是隐式的,由编译程序根据实参的类型自动地把函数模板实例化为具体的函数,这种确定函数模板实例的过程叫做模板实参推演(template argument deduction)。 例如: int a[100]; sort(a,100); //调用void sort(int elements[], unsigned int count) double b[200]; sort(b,200); //调用void sort(double elements[], unsigned int count) A c[300]; //类A中需重载操作符:<,需要时还应自定义拷贝构造函数和=。 sort(c,300); //调用void sort(A elements[], unsigned int count)

有时,编译程序无法根据调用时的实参类型来确定所调用的模板函数,这时,需要在程序中显式地实例化函数模板。显式实例化时,在调用模板函数时需要向函数模板提供实参。 例如: template <class T, int size> void f(T a) { T temp[size]; ...... } int main() { f<int,10>(1); //调用模板函数f(int a),该函数体中的size为10

函数模板和函数重载的配合使用 问题:max(x,m) 调用哪一个模板函数? template <class T> T max(T a, T b) { return a>b?a:b; } ...... int x,y,z; double l,m,n; z = max(x,y); //调用模板函数:int max(int a,int b) l = max(m,n); //调用模板函数:double max(double a,double b) 问题:max(x,m) 调用哪一个模板函数?

解决办法: 显式实例化 max<double>(x,m); 或 max<int>(x,m); 再定义一个max的重载函数 double max(int a,double b) { return a>b?a:b; }

类模板 其中,T1、T2等为类模板的类型参数,在类成员的说明中可以用T1、T2等来说明它们的类型。 如果一个类的成员的类型可变,则该类称为类属类。类属类一般用类模板实现,其格式为: template <class T1,class T2,...> class <类名> { <类成员说明> } 其中,T1、T2等为类模板的类型参数,在类成员的说明中可以用T1、T2等来说明它们的类型。

例如:定义一个可表示各种类型元素的栈类。 template <class T> class Stack { T buffer[100]; int top; public: Stack() { top = -1; } bool push(const T &x); bool pop(T &x); }; bool Stack <T>::push(const T &x) { ...... } bool Stack <T>::pop(T &x) { ...... }

除了类型参数外,类模板也可以包括非类型参数。 例如: template <class T, int size> class Stack { T buffer[size]; int top; public: Stack() { top = -1; } bool push(const T &x); bool pop(T &x); }; template <class T,int size> bool Stack <T,size>::push(const T &x) { ...... } bool Stack <T,size>::pop(T &x) { ...... }

Stack类 #include <iostream.h> using namespace std; const int STACK_SIZE=100; class Stack { int top; int buffer[STACK_SIZE]; public: Stack() {top=-1;} bool push(int i) { if(top==STACK_SIZE-1) {…… } else{ top++; buffer[top]=i; return true;} } bool pop(int &i) { if(top== -1) {……} else { i=buffer[top]; top--; return true; } };

类模板的使用 类模板定义了若干个类,在使用这些类之前,编译程序将会对类模板进行实例化。类模板的实例化需要在程序中显式地指出。例如: Stack<int> st1; //创建一个元素为int型的栈对象。 int x; st1.push(10); st1.pop(x); Stack<double> st2; //创建一个元素为double型的栈对象。 double y; st2.push(1.2); st2.pop(y); Stack<A> st3; //创建一个元素为A类型的栈对象(A为定义的一个类)。 A a,b; st3.push(a); st3.pop(b);

类模板中的静态成员仅属于实例化后的类(模板类),不同类模板实例之间不共享类模板中的静态成员。例如: template <class T> class A { static int x; T y; ...... }; template <class T> int A<T>::x=0; A<int> a1,a2; //a1和a2共享一个x。 A<double> a3,a4; //a3和a4共享另一个x。

模板的复用 一个模板可以有很多的实例。是否实例化模板的某个实例要由使用情况来决定。 例如: // file1.cpp #include "file2.h" int main() { S<float> s1; //实例化“S<float>”并创建该类的一个对象s1。 s1.f(); //调用void S<float>::f() S<int> s2; //实例化“S<int>”并创建该类的一个对象s2。 s2.f(); //Error,连接程序将指出:“void S<int>::f()”不存在。 sub(); return 0; }

// file2.h template <class T> class S //类模板s的定义 { T a; public: void f(); }; extern void sub(); // file2.cpp #include "file2.h" void S<T>::f() //类模板s的实现 { ...... } void sub() { S<float> x; //实例化“S<float>”并创建该类的一个对象x。 x.f(); //实例化:void S<float>::f()并调用之。

解决上述问题的通常做法是把模板的定义和实现都放在头文件中。 // file2.h template <class T> class S //类模板s的定义 { T a; public: void f(); }; void S<T>::f() //类模板s的实现 { ...... } extern void sub();

// file1.cpp #include "file2.h" int main() { S<float> s1; //实例化“S<float>”并创建该类的一个对象s1。 s1.f(); //实例化:void S<float>::f()并调用之。 S<int> s2; //实例化“S<int>”并创建该类的一个对象s2。 s2.f(); //实例化:void S<int>::f()并调用之。 sub(); return 0; } // file2.cpp void sub() { S<float> x; //实例化“S<float>”并创建该类的一个对象x。 x.f(); //实例化:void S<float>::f()并调用之。

C++标准模板库(STL) 在C++标准库中,除了从C标准库保留下来的一些功能外,所提供的功能大都以模板形式给出,这些模板构成了C++的标准模板库(Standard Template Library,简称STL)。 STL主要包含: 常用的算法(函数)模板(如:排序函数模板、查找函数模板等) 容器类模板(如:集合类模板、栈类模板等) 迭代器类模板,实现了抽象的指针功能,用于对容器中的数据元素进行遍历和访问。