C++中的多態與虛函數的外部完成辦法。本站提示廣大學習愛好者:(C++中的多態與虛函數的外部完成辦法)文章只能為提供參考,不一定能成為您想要的結果。以下是C++中的多態與虛函數的外部完成辦法正文
1、什麼是多態
多態性可以復雜概括為“一個接口,多種行為”。
也就是說,向不同的對象發送同一個音訊, 不同的對象在接納時會發生不同的行為(即辦法)。也就是說,每個對象可以用自己的方式去呼應共同的音訊。所謂音訊,就是調用函數,不同的行為就是指不同的完成,即執行不同的函數。這是一種泛型技術,即用相反的代碼完成不同的舉措。這表現了面向對象編程的優越性。
多態分為兩種:
(1)編譯時多態:次要經過函數的重載和模板來完成。
(2)運轉時多態:次要經過虛函數來完成。
2、幾個相關概念
(1)掩蓋、重寫(override)
override指基類的某個成員函數為虛函數,派生類又定義一成員函數,除函數體的其他局部都與基類的成員函數相反。留意,假如只是函數名相反,形參或前往類型不同的話,就不能稱為override,而是hide。
(2)重載(overload)
指同一個作用域出生多個函數名相反,但是形參不同的函數。編譯器在編譯的時分,經過實參的個數和類型,選擇最終調用的函數。
(3)隱藏(hide)
分為兩種:
1)部分變量或許函數隱藏了全局變量或許函數
2)派生類擁有和基類同名的成員函數或成員變量。
發生的後果:使全局或基類的變量、函數不可見。
3、幾個復雜的例子
/******************************************************************************************************
* File:PolymorphismTest
* Introduction:測試多態的一些特性。
* Author:CoderCong
* Date:20141114
* LastModifiedDate:20160113
*******************************************************************************************************/
#include "stdafx.h"
#include <iostream>
using namespace std;
class A
{
public:
void foo()
{
printf("1\n");
}
virtual void fun()
{
printf("2\n");
}
};
class B : public A
{
public:
void foo() //由於基類的foo函數並不是虛函數,所以是隱藏,而不是重寫
{
printf("3\n");
}
void fun() //重寫
{
printf("4\n");
}
};
int main(void)
{
A a;
B b;
A *p = &a;
p->foo(); //輸入1。
p->fun(); //輸入2。
p = &b;
p->foo(); //輸入1。由於p是基類指針,p->foo指向一個具有固定偏移量的函數。也就是基類函數
p->fun(); //輸入4。多態。雖然p是基類指針,但實踐上指向的是一個子類對象。p->fun指向的是一個虛函數。依照靜態類型,調用子類函數
return 0;
}
4、運轉時多態以及虛函數的外部完成
看了上邊幾個復雜的例子,我豁然開朗,原來這就是多態,這麼復雜,明白啦!
好,那我們再看一個例子:
class A
{
public:
virtual void FunA()
{
cout << "FunA1" << endl;
};
virtual void FunAA()
{
cout << "FunA2" << endl;
}
};
class B
{
public:
virtual void FunB()
{
cout << "FunB" << endl;
}
};
class C :public A, public B
{
public:
virtual void FunA()
{
cout << "FunA1C" << endl;
};
};
int _tmain(int argc, _TCHAR* argv[])
{
C objC;
A *pA = &objC;
B *pB = &objC;
C *pC = &objC;
printf("%d %d\n", &objC, objC);
printf("%d %d\n", pA, *pA);
printf("%d %d\n", pB, *pB);
printf("%d %d\n", pC, *pC);
return 0;
}
運轉後果:
5241376 1563032
5241376 1563032
5241380 1563256
5241376 1563032
細心的同志一定發現了pB出了問題,為什麼明明都是指向objC的指針,pB跟他人的值都不一樣呢?
是不是編譯器出了問題呢?
當然不是!我們先講結論:
(1)每一個含有虛函數的類,都會生成虛表(virtual table)。這個表,記載了對象的靜態類型,決議了執行此對象的虛成員函數的時分,真正執行的那一個成員函數。
(2)關於有多個基類的類對象,會有多個虛表,每一個基類對應一個虛表,同時,虛表的順序和承繼時的順序相反。
(3)在每一個類對象所占用的內存中,虛指針位於最前邊,每個虛指針指向對應的虛表。
先從復雜的單個基類說起:
class A
{
public:
virtual void FunA()
{
cout << "FunA1" << endl;
}
virtual void FunA2()
{
cout << "FunA2" << endl;
}
};
class C :public A
{
virtual void FunA()
{
cout << "FunA1C" << endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A *pA = new A;
C *pC = new C;
typedef void (*Fun)(void);
Fun fun= (Fun)*((int*)(*(int*)pA));
fun();//pA指向的第一個函數
fun = (Fun)*((int*)(*(int*)pA) +1);
fun();//pA指向的第二個函數
fun = (Fun)*((int*)(*(int*)pC));
fun();//pC指向的第一個函數
fun = (Fun)*((int*)(*(int*)pC) + 1);
fun();//pC指向的第二個函數
return 0;
}
運轉後果:
FunA1
int _tmain(int argc, _TCHAR* argv[])
{
C objC;
A *pA = &objA;
B *pB = &objC;
C *pC = &objC;
typedef void (*Fun)(void);
Fun fun = (Fun)*((int*)(*(int*)pC));
fun();//第一個表第一個函數
fun = (Fun)*((int*)(*(int*)pC)+1);
fun();//第一個表第二個函數
fun = (Fun)*((int*)(*((int*)pC+1)));
fun();<span > </span>//第二個表第一個函數
fun = (Fun)*((int*)(*(int*)pB));
fun();//pB指向的表的第一個函數
return 0;
}
哈哈,和我們的猜想完全分歧:
FunA1C以上就是為大家帶來的C++中的多態與虛函數的外部完成辦法全部內容了,希望大家多多支持~