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