文章目錄
- 一、多態是什么?
- 二、使用步驟
- 2.1. 靜態多態
- 2.1.1 函數重載
- 2.1.2 模板
- 2.2.動態多態
- 2.2.1 示例
- 2.2.2 原理分析
- 總結
一、多態是什么?
多態是面向對象的語言中都必須掌握的特性,其概念簡單講就是對同一種特性的方法有不同的實現功能,例如玩手機這個方法,有人玩抖音,有人玩LOL等等種不同的應用形式。
多態可以按照綁定分為靜態多態和動態多態。
綁定是指函數體與函數調用完成關聯的過程。
靜態多態是指在程序編譯期間就完成,一般通過函數重載和模板來完成,會根據函數實參的類型或個數來選擇那個函數來實現。
動態多態是指在程序編譯后完成的聯編,通過虛方法的形式完成,根據引用對象的實際類型調用相應的方法。其原理就是用父類的虛函數指針去調用子類中被重寫的方法。
二、使用步驟
2.1. 靜態多態
2.1.1 函數重載
下面為構造函數重載示例:
class Cat
{
public:Cat(){cout << "喵是無參構造函數" << endl;}Cat(string name){Name = name;cout << "喵是有參構造函數" << endl;}//用于拷貝c的屬性值,用常量引用的方式進行Cat(const Cat &c){Name = c.Name;cout<< "喵是拷貝構造函數" << endl;}~Cat(){cout << "喵是析構函數" << endl;}string Name;//咪咪名字
};void FindName()
{//括號法Cat cat1;//用默認構造函數時,不能加括號,否則編譯器會當作函數聲明。Cat cat2(cat1);//拷貝構造函數調用Cat cat3("小300");//有參構造函數調用。Cat cat4(cat3);//拷貝構造函數調用cout << "第一個貓的名字是:" << cat1.Name << endl;cout << "第二個貓的名字是:" << cat2.Name << endl;cout << "第三個貓的名字是:" << cat3.Name << endl;cout << "第四個貓的名字是:" << cat4.Name << endl;
}
2.1.2 模板
模板在C++中分為類模板和函數模板,用template修飾,和泛型的概念很相似。
類模板是通過建立一個通用類,其中的數據成員、成員函數的返回值類型和形參類型不進行具體指定,用一個虛擬的類型聲明。在使用類模板定義對象時,系統會實參的類型來取代類模板中虛擬類型從而實現了不同類的功能。
函數模板也需聲明一個模板類名,然后在函數形參中聲明一個模板類對象,在進行函數調用時會根據實參的類型來覆蓋模板類。
函數模板調用規則:
1.如果函數模板和普通函數都可以實現功能的話優先調用普通函數。
2.可以通過空模板參數列表來強制調用函數模板。
3.函數模板可以發生重載。
4.如果函數模板可以產生更好的匹配,優先調用函數模板。
類模板和函數模板的區別:
1:類模板沒辦法對聲明的模板類對象進行自動推導類型,必須用指定類型,函數模板可以。
2:類模板在模板參數聲明時可以有默認參數類型,比如在聲明構造函數時一個形參為模板類型,一個為int類型。
類模板
#include <iostream>
#include<string>
using namespace std;template<class T1, class T2>class Person
{
public:Person(T1 name, T2 age){this->m_age = age;this->m_name = name;}void showPerson(){cout << m_name <<" "<< m_age << endl;}private:T1 m_name;T2 m_age;
};int main()
{Person<string, int> p("張三", 1);p.showPerson();system("pause");return 0;
}
函數模板
#include <iostream>
using namespace std;template<class T>//T的類型需要一致,選擇排序
void Sort(T arr[], int l)
{for (int i = 0; i < l; i++){int max = i;for (int j = i + 1; j < l; j++){if (arr[max] > arr[j]){max = j;}}if (max != i){T temp = arr[max];arr[max] = arr[i];arr[i] = temp;}}
}int main()
{int Array[] = {1,4,35,24,213,2132};int num = sizeof(Array) / sizeof(int);Sort(Array, num);//Sort<>(Array, num);//空模板參數列表for(int i = 0; i< num; i++){cout << Array[i] << endl;}system("pause");return 0;
}
2.2.動態多態
動態多態需滿足以下條件:
1.類之間存在繼承關系
2. 調用函數的對象必須是指針或者引用。
3.子類重寫父類函數(函數返回值、名稱和參數列表相同)
2.2.1 示例
#include<iostream>
using namespace std;class Student
{
public://虛函數virtual void play(){cout << "我在玩手機" << endl;}//純虛函數,純虛函數的類為抽象類,類無法實例化/*virtual void play() = 0;*///父類寫虛析構函數virtual ~Student(){}
};class Student1 :public Student
{
public:Student1(string app){APP = new string(app);}void play(){cout << "我在刷" << *APP << endl;}//如果沒有在堆區開辟內存的化,不用寫~Student1(){if (APP != NULL){delete APP;APP = NULL;}}private:string *APP;
};class Student2 :public Student
{
public:Student2(string app){APP = new string(app);}void play(){cout << "我在玩" << *APP << endl;}~Student2(){if (APP != NULL){delete APP;APP = NULL;}}
private:string* APP;
};int main()
{//父類指針在調用自身的析構函數時,不會調用子類的析構,從而造成內存泄露,所以要改為虛析構的方法。Student* s1 = new Student1("抖音");s1->play();delete s1;Student* s2 = new Student2("LOL");s2->play();delete s2;
}
2.2.2 原理分析
同樣可以使用開發者工具進行分析。
其中vfptr指的是虛函數指針,vftable指的是虛函數表,父類子類中均存在虛函數指針和表,其中指針指向虛函數表。在進行虛函數的重寫時,就會產生子類的虛函數指針,通過聲明父類指針或引用調用函數時,就會覆蓋vftable中類名,指向對應子類中的重寫方法。
總結
多態的概念使C++的編程非常靈活,需要特別注意開閉原則和內存管理。