1. 多态定义:不同的派生类对于基类的同一接口的不同反应;
作用:提高程序的扩展性,减轻系统升级、维护、调试的工作量和复杂度;
2. 向上类型转型:派生类→基类; 向下类型转型:基类→派生类;
3. 多态产生的条件
(1)存在继承关系;(2)派生类重写基类的方法,基类的方法用virtual修饰;(3)用基类的指针或引用调用派生类对象的指针或引用;
4. 多态的分类
(1)静多态(编译时绑定):①函数重载,通过函数重命名在编译阶段决定;②模板;
(2)动多态(运行时绑定):(继承中的)虚函数;
5. 虚函数注意事项
(1)基类中利用virtual修饰析构函数,可以在利用基类指针释放派生类指针时使用;即基类的析构函数也是虚函数;
(2)可以利用关键字override放在派生类虚函数后面,用来派生类的这个函数有没有遮蔽/覆盖基类中的虚函数;
(3)在派生类中覆写基类中的函数时,要求函数名、返回值类型、函数参数个数及类型必须全部匹配;
(4)关键字final,若放在类的后面,如class Test final{},表示禁止其他类继承;若final修饰虚函数时,则禁止子类重载;
(5)一些限制
①只有类的成员函数才能声明为虚函数;
②静态成员函数(被static修饰的)不能是虚函数;
③内联函数不能是虚函数;
④构造函数不能是虚函数(因为构造函数本身就是给自己的类初始化的);
⑤析构函数可以是虚函数且通常声明为虚函数(详见5-(1));
多态示例:
#include <iostream>
using namespace std;
class A
{
public:
A()
{
}
virtual void print()
{
cout<<"print A"<<endl;
}
virtual ~A()
{
cout<<"~A"<<endl;
}
};
class B : public A
{
public:
B()
{
}
void print()
{
cout<<"print B"<<endl;
}
~B()
{
cout<<"~B"<<endl;
}
};
class C : public A
{
public:
C()
{
}
void print()
{
cout<<"print C"<<endl;
}
};
void test(A *a)
{
a->print();
}
int main(int argc, char **argv)
{
A a;
B b;
C c;
test(&a); //这里分别打印ABC类自己的成员函数,实现多态
test(&b);
test(&c);
A *a1;
B *b1 = new B();
a1 = b1;
delete a1; //这里利用基类的指针释放派生类的指针,就需要将基类的析构函数变更为虚函数,前面加virtual,否则只析构A
return 0;
}
6. 抽象类
(1)纯虚函数定义:是指在一个类里的成员函数,即是虚函数(virtual修饰的),同时也只有声明没有定义,则是虚函数,形式如下:
virtual test(int num, int len) = 0;
(2)抽象类定义:如果一个类里面有纯虚函数,那么这个类就是抽象类;
(3)抽象类的特点:只可以定义指针或引用,不可以实例化对象;
(4)抽象类的作用:充当功能接口或者类接口,依赖于抽闲类编程;
(5)派生类继承的时候,必须全部将基类的纯虚函数覆写并定义,若遗漏一个,那么该派生类也是抽象类,也无法实例化对象;
抽象类继承示例:
#include <iostream>
using namespace std;
class A
{
public:
A()
{
}
virtual void print(int num, int len) = 0;
};
class B : public A
{
public:
B()
{
}
void print(int num, int len)
{
cout<<"print B = "<<(num+len)<<endl; //+
}
};
class C : public A
{
public:
C()
{
}
void print(int num, int len)
{
cout<<"print C = "<<(num*len)<<endl; //*
}
};
int main(int argc, char **argv)
{
A *a1 = new B();
A *a2 = new C();
a1->print(3,4);
a2->print(3,4);
return 0;
}
(6)依赖倒置原则:要依赖于抽象,让变化的依赖于不变的,妈妈讲故事的案例,妈妈要讲很多故事,要制作一个故事的抽象类,这样有新的故事时,扩展性就很好,即不用修改现有代码,只需要新增类去继承这个故事的抽象类即可,如下所示:
#include <iostream>
#include <string>
using namespace std;
class AbsStory
{
public:
virtual string getcontant() = 0;
};
class Book1:public AbsStory
{
public:
string getcontant()
{
return "西游记";
}
};
class Book2:public AbsStory
{
public:
string getcontant()
{
return "哪吒脑海";
}
};
class Book3:public AbsStory
{
string getcontant()
{
return "拔苗助长";
}
};
class Mother
{
public:
void tell_story(AbsStory *b)
{
cout<<"妈妈讲";
cout<<b->getcontant();
cout<<"的故事"<<endl;
}
};
int main(int argc, char **argv)
{
AbsStory * s1;
s1 = new Book3(); //讲不同的故事,只需要改123数字即可,新增故事,只需要新增类即可
Mother m1;
m1.tell_story(s1);
return 0;
}