c到c++过度 第4天
本帖最后由 代号3 于 2018-4-30 11:40 编辑多态 模版
数组中保存不同类型的对象:在多个类之上增加一个父类 数组使用父类的类型
后遗症:
数据保存不完整 高精度赋值给低精度精度丢失
解决:不保存完整对象 保存对象的地址 指针数组
父类通过数组元素调用成员函数时不能调用子类成员函数
解决:创建虚函数 前边加virtual (类型前) 父类中函数声明为虚函数
多态
对相同的指令做出不同的应答
实现
静态联编 (早期联编) 默认方式
重载
重定义
都会在编译阶段确定具体使用怎样的应答(函数体)来回应指令(函数调用)
动态联编 多态基础(晚期联编) ?静态地位//有多即动 非多即静
特定场合调用虚函数
父类指针调用虚函数的时候能够动态识别出指针指向类型,自动指向该类型同名
成员函数
触发
必须被调用函数为虚函数 否则默认静态联编
使用父类指针指向子类对象
使用父类指针调用虚函数
eg:
class Animal{};
calss Dog:public Animal{};
int main
{
Animal aniObj;
Dog dogObj;
Animal *pAni=nullptr;
Dog*pDog=nullptr;
aniObj.sound();//不会触发 调用Animal类的函数
dofObj.sound();
pAni=&anObj;
pAni->sound();//不会触发 调用Animal类的函数
pDog=&dogObj;
pDog->sound();//不会触发 调用Dog类函数
pAni=&dogObj;
pAni->sound();//会触发 调用Dog类函数此时调用函数为虚函数 父类指针指向子类对象
}
多态原理
动态联编之后 父类指针如何识别出指针指向哪个子类对象 ?重载// 满足重写才能实现重载
虚函数表
当一个类有一个及以上的虚函数时 这个类定义出的对象大小会增加4个字节
(在对象的首地址处 内容为地址(虚函数表))
地址(虚函数表)储存的是一个数组
数组内存档地址(内容为子类对象的函数地址)) 此时就可以调用子类对象中的函数
增加虚函数的时候 虚函数列表增加 ?指针移位实现//编译器自主决定
//虚函数表只有一个内容可多个(重编译解决数组大小问题) 虚函数可以多个
子类重新实现一个虚函数 虚函数表保存的是子类的虚函数地址(子类作为父类时实现多态)
几个 重写?还是另写// 全部刷新 父类被覆盖 不能再被使用
子类没有重新实现虚函数 虚函数表保存的是父类的地址
虚函数
定义
virtual+基类中的成员函数编译器会认为该成员函数可能在派生类中存在不同的实现版本
使用
基类中的函数说明为虚函数
定义基类的公有类派生 基类的公有派生类中重写虚函数(基虚子皆虚)
重写虚函数不是重载函数要求全部相同
基类派生重写可以省略virtual
功能
允许函数调用与函数体的联系在运行时才动态给出
原理
指针保存不同对象
限制条件
类的成员函数才能说明为虚函数 虚函数仅适用与有继承关系的类对象
静态成员函数不能是虚函数 无法构成重写
正常一个子类被释放时会主动调用其父类的析构函数
使用父类指针指向子类对象 当释放该父类指针时 会调用父类的析构函数
此时子类中若有堆内存的申请 会造成内存泄露(delete基类指针只调用父类的析构函数
子类不被调用)
解决:
将析构函数定义为虚函数(构造函数不能是虚函数 析构可以) ?//非唯一 自动调用析构时使用
重载 重定义 重写异同
作用域 函数名 参数
重载 相同 相同 不同 overload
重定义 不同 相同 相同 /不同 override
重写 不同 相同 相同 overwrite
重写 ?实现原理 重定义?//虚函数列表实现动态联编
子类虚函数覆盖基类虚函数
特征
不同范围(子类与基类)
函数名相同
参数相同
基类函数中必须有virtual关键字
纯虚函数
在基类中不对虚函数给出有意义的实现 仅作为统一的编程接口使用 实现留给该基类
的派生类去做
语法格式
class <类名>
{
virtual <函数类型 ><函数名>(<参数表>)=0;
}
抽象类
一个类中定义了纯虚函数(一个或以上) 这个类会变成抽象类
只能作为基类用
抽象类不能直接实例化创建(不能声明抽象类对象) 可以声明抽象类的指针和引用
可使用指向抽象类的指针支持运行时多态性
继承抽象类必须重写所有虚函数 否则此类仍然是抽象类
若是子类继承基类抽象类 给出虚函数
?//纯虚函数未实现子类中重写父类虚函数 此时虚函数表为子类
子类型
特定类型s当且仅当至少提供了类型t的行为s称 s类型是类型t的子类型
s可以有新的行为
子类型关系不可逆
模板
函数模板
类模板 加class
限制条件
成员函数在类外定义的时候必须要放在同一个头文件里。加类名
(不能在.cpp中 会报错且不好查找)
语法
template<参数化类型名表>
<返回类型><函数名>(<参数表>)
{
函数体
}
eg:
template<typename T_Type>
int fun(T_Type NumA,T_Type NumB,~~~~~~)
{
}
类类型需要加关键字class
template <class T_Type>
{}
函数模版是模板的定义 不是函数 定义中使用通用的类型参数
模板函数是用函数模板实例化的函数,是事实上的函数定义。
模板函数
函数名(实参数),当实参数与函数模板参数相匹配的时候,则产生一个重载函数。
重载函数与函数模板实现功能相同(函数体定义相同)则成该重载函数为模板函数。
模板特化(实例化)
偏特化
所有类型的某一种类型的某几项进行特别处理
普通特化
模板所有替换类型的某一类型进行特别处理
页:
[1]