目录
一、虚函数和多态
1. 引入多态和虚函数
多态: 通俗理解就是多种表现形式 -> 同一个接口有多种表现形式
父类的指针或者父类的引用指向子类对象,你传递参数的时候传递的是子类A就调用A的方法,传递的是子类B就调用B的方法 -> C++把这种技术称作多态
虚函数: 在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数,实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。
用法格式为
virtual 函数返回类型 函数名(参数表)
{
函数体
};
2.多态实现的前提条件
①必须要有继承,有了继承C++语法才允许你父类的指针或者父类的引用指向子类对象
②父类的同名函数必须定义成虚函数
③子类必须重写父类的同名方法
3. 原理
①只要一个类中定义了虚函数,那么这个类以及它派生出来的类都会有各自独立的虚函数表,并且创建的对象中会多出来一个指针(该指针指向虚函数表的首地址)
②父类的指针或者父类的引用去调用方法的时候,其实就是去查询虚函数表
4.C++中多态可以划分为两大类
第一类:编译时多态 -> 函数重载就是编译时多态
第二类:运行时多态 -> 我们现在用虚函数实现的这种就是运行时多态
二、类的包含 ->类的嵌套
类的嵌套:一个类的对象作为另外一个类的成员
class Book
{
public:
Book()
{
}
Book(string newname)
{
bookname=newname;
}
private:
string bookname;
};
//定义读者类
class Reader
{
public:
void getBook(Book &newbook)
{
somebook=newbook;
}
private:
Book somebook; //调用无参构造函数
};
三、纯虚函数和抽象类
1. 纯虚函数:
(1)跟虚函数的关系
纯虚函数是虚函数的一种特殊情况
(2)语法
virtual 函数返回值 函数名字()=0;//纯虚函数没有任何具体代码,只有一个声明
(3)作用
提供一个统一接口,实现要求程序员根据自己的情况各自去实现(要前向引用声明)
2. 抽象类
(1)定义
只要一个类中声明了纯虚函数,那么这个类就是抽象类
(2)作用
跟纯虚函数配合,提供接口声明给程序员,提供给程序员提供的共同的操作接口,程序员依照统一的接口去实现各自的功能
(3)特点
①抽象类是不能定义对象的
②一个类继承了抽象类,必须实现抽象类中所有的纯虚函数,如果有一个不实现,那么子类依然是抽象类
③抽象类也可以定义构造函数,作用用于子类新建对象的时候会调用父类(抽象类)的构造方法
(4)常见的错误
①子类没有将父类(抽象类)中的纯虚函数都实现
②子类“实现了父类(抽象类)中所有的纯虚函数”,函数类型不一样
例:
class 父类
{
public:
virtual void show()=0;
}
class 子类:public 父类
{
public:
void show(string name)
{
cout<<name<<endl;
}
}
四、虚析构函数
1. 析构函数只有一种写法
virtual ~类的名字()
{
函数体;
}
2.作用
父类的指针指向子类对象的时候,delete释放父类指针,默认只会调用父类的析构,不会调用子类的析构(万一子类中有堆空间没有释放怎么办呢??)
解决方法: 在父类的析构函数前面加上virtual关键字即可
注意:只要代码中涉及到继承,你都把父类的析构函数定义成虚析构
五、友元函数和友元类
1. 引入友元
C++提供了不需要使用继承,直接就能访问其他类的所有成员的一种机制
2.特点
①友元是单向
比如:A是B的友元,但是你不能B也是A的友元
②友元是不能传递,也不能继承的
比如:A是B的友元,A是C的友元,不能认为B和C也是友元关系
A是B的友元,不能认为A的子类也是B的友元
3. 友元的几种情况
①普通函数作为一个类的友元
friend void getCardMsg(Card &card);
② 一个类的成员函数作为另外一个类的友元(注意写法,很容易写错)
friend void People::getCardMoney(Card &card);
③友元类,一个类整体作为另外一个类的友元
firiend class Card;
4. 友元的优点缺点
(1)优点
①提供了一种可以直接访问类的私有,保护,公有成员的一种方法(不需要通过继承,不需要通过修改权限,只需要声明成友元)
②提高了程序的运行效率(减少了系统用于安全性检查的时间消耗,编译器不用再去检查你定义的权限)
(2)缺点
破坏了类的封装性
六、模板函数和模板类(泛型编程)
泛型:通用的类型
1. 引入模板
C++把函数参数的类型抽象出来 -> 定义成模板
2. 模板函数
(1)定义
只要一个函数中使用了模板,这个函数就叫做模板函数
例:
int add(int a,int b)
double add(double a,double b)//函数重载
T add(T a,T b)//模板
(2)语法
template <class 模板的名字,class 模板的名字>//声明一个模板
template <typename 模板的名字,typename 模板的名字> //typename和class都是一样的作用
函数的定义
{
函数体;
}
(3)特点
①每个模板函数必须单独声明模板,不能共用同一个模板
②模板函数跟具体版本的函数混合在一起,优先使用具体版本的函数
编译器会通过你传递的实参的类型去实例化模板函数(翻译你的模板函数为具体类型的函数)
3. 模板类
(1)定义
只要一个类中使用了模板,这个类称作模板类
template<class T> //模板类
class Pic
{ };
Pic<int> a;//定义对象
(2)语法
template <class 模板的名字,class 模板的名字>//声明一个模板
class 类名
{
模板的名字 属性名;
}
类名<类型>对象;//使用