多 態
1、動態多態的實現原理
2、多態的類別及實現方法
3、動態多態的四種情況
(2)多態的類別及實現方法
2.1 靜態多態:編譯時多態、函數的多態性,重載、模板、宏
2.2 動態多態:運行時多態、類的多態性,繼承和虛函數,晚綁定、動態綁定
2.3 封裝可以使得代碼模塊化,繼承可以擴展已存在的代碼,他們的目的都是爲了代碼重用。而多態的目的則是爲了接口重用。也就是說,不論傳遞過來的究竟是哪個類的對象,函數都能夠通過同一個接口調用到適應各自對象的實現方法。
(3)動態多態的四種情況
3.1 用一個父類的指針指向一個子類對象
3.2 用一個父類的指針當函數的形參,用這個指針可以接受到任何它的子類對象也包括他自己
3.3 在複合類,儘量飲用高層次的類(父類的指針)當做類的成員變量,這樣就可以通過它創建出它所對應的任何子類對象包括他自己
3.4 在容器中,可以聲明一個父類指針的容器,這時可以往容器中添加它所對應的任何子類對象包括他自己
//這裏“隱藏”是指派生類的函數屏蔽了與其同名的基類函數,規則如下:
//(1)如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無virtual關鍵字,基類的函數將被隱藏(注意別與重載混淆)。
//(2)如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數沒有virtual關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)。
//上面的程序中:
//(1)函數Derived::f1(float)覆蓋了Base::f1(float)。
//(2)函數Derived::f2(int)隱藏了Base::f2(float),而不是重載。
//(3)函數Derived::f3(float)隱藏了Base::f3(float),而不是覆蓋
#ifndef __C__No807Class__Father__
#define __C__No807Class__Father__
#include <iostream>
using namespace std;
class Father
{
public:
virtual void print();
};
#endif /* defined(__C__No807Class__Father__) */
#include "Father.h"
void Father::print()
{
cout << "Father print" << endl;
}
#ifndef __C__No807Class__Son__
#define __C__No807Class__Son__
#include <iostream>
#include "Father.h"
class Son : public Father
{
public:
void print();
};
#endif /* defined(__C__No807Class__Son__) */
#include "Son.h"
void Son::print()
{
cout << "Son print" << endl;
}
#ifndef __C__No807Class__Son2__
#define __C__No807Class__Son2__
#include <iostream>
#include "Father.h"
class Son2 : public Father
{
public:
void print();
};
#endif /* defined(__C__No807Class__Son2__) */
#include "Son2.h"
void Son2::print()
{
cout << "Son2 print" << endl;
}
#include <iostream>
#include<string>
#include<vector>
#include "Son.h"
#include "Son2.h"
//如果容器中函數的對象是不同類的,那麼這時候用使用多態是非常的方便的
void func(const vector<Father*>&V) //容器中,可以聲明一個父類指針的容器,可以往這個容器中添加它所對應的任何子類對象包括他自己
{
for(int i = 0; i < V.size(); ++i)
{
V.at(i) -> print();
}
}
void foo(Father &f) //父類指針當函數形參,用這個指針可以接受到任何它的子類對象也包括他自己
{
f.print(); //Son,不加引用Father
}
int main()
{
Son s;
Son2 s2;
Father f;
Father *p;
p = &s; //父類指針指向子類對象
p -> print();
p = &s2;
p -> print();
foo(s);
vector<Father*>FatherVector;
FatherVector.push_back(&s);
FatherVector.push_back(&s2);
FatherVector.push_back(&f);
func(FatherVector);
return 0;
}
B、靜態多態--重載
#include <iostream>
#include <string>
using namespace std;
int add (int num1, int num2)
{
return (num1 + num2);
}
int add (int num1, string str1)
{
return (num1 + atoi(str1.c_str())); //把字符串的數字轉爲數字型的數值
}
int add (int num1, char c1)
{
return (num1 + c1);
}
int main()
{
int n1 = 10, n2 = 20;
string s1 = "30";
char c1 = 'a';
cout << n1 << " + " << n2 << " = " << add(n1, n2) <<endl;
cout << n1 << " + " << s1 << " = " << add(n1, s1) <<endl;
cout << n1 << " + " << c1 << " = " << add(n1, c1) <<endl;
return 0;
}
C、靜態多態--模板
template <typename T>
T max(const T& i, const T& j)
{
return (i > j) ? i : j;
}
//返回兩個任意類型對象的最大值(對象),前提是該類型能夠使用>運算符進行比較,並且返回值是bool類型。
使用:
int a = 3; int b = 4;
cout << max(a, b) << endl;
float c = 2.4; float d = 1.2;
cout << max(c, d) << endl;
輸出結果爲:
4
2.4
這種綁定發生在編譯期,這是由於模板的實例化是發生在編譯期的,即在編譯時編譯器發現你調用max(a, b)時就自動生成一個函數
int max(const int& i, const int& j)
{
return (i > j) ? i : j;
}
即將所有的T替換成int;
當你調用max(c, d)時就自動生成一個函數
float max(const float& i, const float& j)
{
return (i > j) ? i : j;
}
模板2#include<iostream>
#include<string>
#include<vector>
using namespace std;
/*虛函數機制*/
class Base
{
public:
virtual void print()=0;
};
class Child1:public Base
{
void print()
{
cout<<"我是Child1類"<<endl;
}
};
class Child2:public Base
{
void print()
{
cout<<"我是Child2類"<<endl;
}
};
/*如果容器中函數的對象是不同類的,那麼這時候用使用多態是非常的方便的*/
void func(const vector<Base*>&V)
{
for(int i=0;i<V.size();++i)
{
V.at(i)->print();
}
}
/*靜態多態,使用模板*/
template<typename T>
void TempalteFuncion(const vector<T*>&V)
{
for(int i=0;i<V.size();++i)
{
V.at(i)->print();
}
}
int main()
{
/*虛函數多態 模板多態混用*/
Child1 child1;
Child2 child2;
Base *p;
p=&child1;
p->print();
p=&child2;
p->print();
vector<Base*>BaseVector;
BaseVector.push_back(&child1);
BaseVector.push_back(&child2);
func(BaseVector);
TempalteFuncion(BaseVector);
return 0;
}
D、靜態多態--宏多態(忽略)#include<iostream>
#include<string>
using namespace std;
#define ADD(A,B) ((A)+(B))
void main()
{
/*宏多態*/
int num1=10;
int num2=20;
string str1="22";
string str2="33";
cout<<"宏多態 ADD(A+B) A+B:"<<ADD(num1,num2)<<endl;
cout<<"宏多態 ADD(A+B) A+B:"<<ADD(str1,str2)<<endl;
}
E、子類指針指向父類對象、隱藏
#include <iostream>
using namespace std;
class A
{
public:
void f1()
{
cout << "1" << endl;
}
virtual void f2()
{
cout << "2" << endl;
}
};
class B : public A
{
public:
void f1()
{
cout << "3" << endl;
}
void f2()
{
cout << "4" << endl;
}
};
int main()
{
A a;
B b;
A *p = &a;
p -> f1(); //1
p -> f2(); //2
p = &b;
p -> f1(); //1
p -> f2(); //4
B *ptr = (B *)&a; //子類指針ptr,父類對象a的引用強制轉化爲B類類型指針
ptr -> f1(); //3
ptr -> f2(); //2
return 0;
}
#include <iostream>
using namespace std;
class Base
{
public:
virtual void f1(float x)
{
cout << "Base f1 (float) = " << x << endl;
}
void f2(float x)
{
cout << "Base f2 (float) = " << x << endl;
}
void f3(float x)
{
cout << "Base f3 (float) = " << x << endl;
}
};
class Derived : public Base
{
public:
void f1(float x)
{
cout << "Derived f1 (float) = " << x << endl; //覆蓋,多態
}
void f2(int x)
{
cout << "Derived f2 (float) = " << x << endl; //隱藏
}
void f3(float x)
{
cout << "Derived f3 (float) = " << x << endl; //隱藏
}
};
int main()
{
Derived d;
Base *pb = &d;
Derived *pd = &d;
pb -> f1(3.14f); //D f1
pd -> f1(3.14f); //D f1
pb -> f2(3.14f); //B f2
pd -> f2(3.14f); //D f2
pb -> f3(3.14f); //B f3
pd -> f3(3.14f); //D f3
return 0;
}
//這裏“隱藏”是指派生類的函數屏蔽了與其同名的基類函數,規則如下:
//(1)如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無virtual 關鍵字,基類的函數將被隱藏(注意別與重載混淆)。
//(2)如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數沒有virtual 關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)。
//上面的程序中:
//(1)函數Derived::f1(float)覆蓋了Base::f1(float)。
//(2)函數Derived::f2(int)隱藏了Base::f2(float),而不是重載。
//(3)函數Derived::f3(float)隱藏了Base::f3(float),而不是覆蓋