初识C++面向对象特性——多态
个人理解,用一句话来概括多态就是:一个接口(函数)能实现不同种方法
C++的多态分为静态多态和动态多态
静态多态:指的就是重载(编译的时候函数地址就已经确定)
动态多态:继承并重写基类的虚函数
关于静态多态(重载),比较简单,下面用两段代码来演示一下
#include<iostream> #include<string> using namespace std; void PrintInp(int a); void PrintInp(string a); int main(void) { int a; cin >> a; PrintInp(a); string str; cin >> str; PrintInp(str); system("pause"); return 0; } void PrintInp(int a) { cout << a << endl; } void PrintInp(string a) { cout << a << endl; }
第一段代码通过重载实现了函数的多态
#include<iostream> using namespace std; class A { public: void func1() { cout << "class A, func1" << endl << endl; } }; class B :public A { public: void func1() { cout << "class B, func1" << endl << endl; } }; int main(void) { A a; B b; a.func1(); b.func1(); system("pause"); return 0; }
第二段代码通过重载实现了类中成员函数的(静态)多态
为什么要使用虚函数来实现动态多态呢,因为存在这种情况:父类想通过多态的特性使用子类的成员函数,如下面代码所示
#include<iostream> using namespace std; class A { public: void func1() { cout << "class A, func1" << endl << endl; } virtual void func2() { cout << "class A, func2" << endl << endl; } }; class B :public A { public: void func1() { cout << "class B, func1" << endl << endl; } }; class C :public A { public: void func2() { cout << "class C, func2" << endl << endl; } }; int main(void) { A a; B b; a.func1(); b.func1(); A* Test = new B; Test->func1(); A* VirTest = new C; VirTest->func2(); system("pause"); return 0; }
执行结果如下
可以看到Test想通过多态特性使用指针调用子类B中的成员函数,但是他调用的仍然是他自己的func1(),为什么会这样?就要从动态多态的实现原理——虚表说起
https://blog.csdn.net/qq_40840459/article/details/80195158
弄清了虚表结构之后回到上面的代码,通过虚函数我们能实现什么操作?虚函数该怎么用来实现(动态)多态?
首先通过虚函数,父类可以调用子类的成员函数
使用方法:
FATHER* A=new SON; A->function();
此时类A调用的function()就是子类中的function
要注意的是虚函数只能通过指针或者引用来达到多态效果,直接实例化一个类然后直接调用虚函数是无法实现多态的
解释一下为什么基类析构函数要写成虚函数
FATHER* A=new SON; delete A;
实际上,在编译器中,析构函数会被特殊处理,他们也是具有多态性的函数。A的类型是子类,所以析构A的时候需要用SON的析构函数,但是如果父类中的析构函数没有使用虚函数,那么delete A在启动虚构函数时,会直接调用父类的析构函数,new SON申请到的空间就没有得到回收,会造成内存泄漏。
关于虚函数对应虚表的地址操作和纯虚函数的相关知识可以查阅下面链接
https://blog.csdn.net/qq_37668377/article/details/81007527
总结一下多态的优点
可替换、可扩展、灵活、使用简单以及接口性(接口行是什么意思还没弄清)