第四部分 面向对象编程与泛型编程
第15章~16章
2015年5月18日 星期五 9:19
第15章 面向对象编程
- 面向对象编程:概述
- 面向对象编程基于三个基本概念:数据抽象,继承和动态绑定。在C++中,用类进行数据抽象,用类派生从一个类继承另一个类,派生类继承基类的成员。动态绑定使编译器能够在运行时觉得使用基类还是派生类中定义的函数
- 定义基类和派生类
- protect成员,不能被类用户访问,但可以被该类的派生类访问
- 派生类,class classname:access-label base-class,访问权限。默认具有private继承
- virtual与其他成员函数
- C++中的函数默认不使用动态绑定,要触发动态绑定,必须满足两个条件。1,只有指定为虚函数的成员函数才能进行动态绑定;2,必须通过基类类型的引用或指针进行函数调用。
- 运行时确定virtual函数的调用
- 编译时确定非virtual调用
- 公有、私有和受保护的继承
- 友元关系与继承,如果派生类想要将自己成员的访问授权授予其基类的友元,必须显示地这样做
- 继承与静态成员,如果基类定义了static成员,则整个继承层次中只有一个这样的成员
转换与继承
- 派生类到基类的转换,使用派生类对象的地址对基类类型的指针进行初始化或赋值,同样,可以使用派生类类型的引用或对象初始化基类类型的引用
- 基类到派生类的转换,不存在(自动)转换
- 构造函数与复制控制,构造和复制控制成员不能继承
- 基类构造函数和复制控制
- 派生类构造函数
- 合成的派生类默认构造函数
- 定义默认构造函数
- 向基类构造函数传递实参
- 复制控制和继承
- 虚析构函数,保证运行适当的析构函数
- 构造函数和析构函数中的虚函数
- 继承情况下的类作用域,派生类的作用域嵌套在基类作用域中
- 名字查找在编译时发生
- 名字冲突与继承,使用作用域操作符访问被屏蔽成员
- 作用域与成员函数,派生类成员函数屏蔽基类同名函数,即使函数原型不同
- 虚函数与作用域
- 纯虚函数
class Disc_item:public Item_base{ public: double net_price(std:size_z) const =0; };
Disc_item discouted; //error, can't define a Disc_item object- 将函数定义为纯虚能够说明,该函数为后代类型提供了可以覆盖的接口,但是这个类中的版本绝不会调用,而且,用户将不能创建Dist_item类型而对象
- 含有(或继承)一个或多个纯虚函数的类是抽象类。除了作为抽象基类的派生类的对象的组成部分,不能创建抽象类型的对象
- 容器与继承
- 基类容器加入派生类型的对象时,只将对象的基类部分保存在容器中
- 因为派生类对象在复制给基类对象时会被”切掉“,所以容器与通过继承相关的类型不能很好地融合
- 句柄类与继承
第16章 模板与泛型编程
- 模板定义
- 定义函数模板,可以声明为inline,
template <typename T> int compare(const T &v1,const T &v2) { if(v1<v2) return -1; if(v2<v1) return 1; return 0; }
- 定义类模板,使用类模板必须显式指定实参,如 Queue <int> qi;
template <class Type> class Queue{ public: Queue(); Type &front(); const Type &front()const; void push(const Type &); void pop(); bool empty() const; private: //...... }
- 模板形参,形参作用域,使用模板形参名字的限定,模板声明
- 模板类型形参,由关键字class或typename后接说明符构成,模板类型形参可作为类型说明符用在模板的任何地方
- 非类型模板形参,template <class T,size_t N>,在调用函数是,非类型形参将用值代替,值得类型在模板形参表中指定
- 定义函数模板,可以声明为inline,
- 实例化
- 模板是一个蓝图,它本身不是类或函数,编译器用模板产生指定的类或函数的特定类型版本,产生模板的特定类型实例的过程称为实例化
- 模板实参推断,要确定应该实例化哪个函数,编译器会查看每个实参,如果相应形参声明为类型形参的类型,则编译器从实参的类型推断形参的类型。从函数实参确定模板实参的类型和值的过程叫做模板实参推断
- 函数模板的显式实参,在某些情况下,不可能推断模板实参的类型,当函数的返回类型必须与形参表中所用的所有类型不同时,最常出现这一问题
- 模板编译模型,模板要进行实例化,编译器必须能够访问定义模板的源代码,有两种模型
- 包含编译模型,编译器必须看到用到的所有模板的定义,一般而言,可以通过在声明函数模板或类模板的头文件中添加一条#include指示使定义可用,该#include引入了包含相关定义的源文件。这种方式可能导致模板的实例化超过一次,在链接的时候,编译器会选择一个实例而丢弃其他的。
- 分别编译模型,编译器会为我们跟踪相关的模板定义,但是,我们必须让我们知道要记住给定的模板定义,可以使用export关键字。
- 类模板成员。介绍如何实现Queue类
- 类模板成员函数
- 非类型形参的模板实参
- 类模板的友元声明,三种声明
- 普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数
- 类模板或函数模板的友元声明,授予对友元所有实例的访问权
- 只授予对类模板或函数模板的特定实例的访问权的友元声明
- 一个泛型句柄类
- 模板特化