C++虚函数---我的理解
先了解一些基礎知識
1.構造函數和析構函數一般是公有成員,否則該類不能實例化
2.類成員默認訪問權限是private類型(strcut默認訪問權限是public)
?
3.析構函數一般是虛函數,否則可能會造成內存泄漏
4.擁有虛函數的的類都會有一個虛表,該虛表的指針位于類的首地址
虛表展示:
?
?
5.沒有虛函數的類,首地址是成員變量(先后順序和在類聲明里面的一直,與公私有無關),
??如果有虛函數,則類的成員變量從第5個位置開始放,前四個位置儲放虛表地址
6.函數編譯產生的地址與inline和virtual無關(產生地址是連續的)
?
7.打印成員變量和函數地址的方法
printf("成員變量m_char的地址:%p\n",&Base::m_char);
printf("成員函數funBase1的地址:%p\n",&Base::funBase1);
8.類空指針訪問成員函數,但是如果drivedFun1是虛函數則會訪問失敗
?
這樣的成員函數(非虛擬函數)與類實體不是存放在一起的。所以你調用時與實體是沒關的。?但是如果是虛函數,就要用到vptr,這個是與類實體有關的,當然就不行了。static函數更是與實體沒關的,也是可以調用的。?如果要深入理解,建議去看《深度探索C++對象模型》
進一步的測試
1.如果類指針沒有訪問類的虛函數和類指針的普通函數沒有訪問成員變量,則即使類指針即使為空該指針一樣可以正常調用該函數(無所謂父類對象轉為子類指針或者子類對象轉為父類指針,甚至無所謂父子類)。
具體例子:
Drived?d;
//Drived?*pDrived?=?(Drived?*)&d;??(2)
Drived?*pDrived?=?NULL;?????????(3)
pDrived->drivedFun1();???????????(4)
代碼行2和代碼行3的賦值結果不會影響到代碼行4的執行結果
?
2.每個擁有虛函數的類都有自己的虛表(下圖展示了父子類虛表地址值的不同)
?
?
3.虛函數好處:父類指針指向子類對象可以調用子類函數,從而實現多態
原理:帶有虛函數的類會產生一個虛表,虛表里有虛函數地址,程序執行時會動態加載
總結:虛函數的好處在于利用父類指針調用子類函數,當然也可以用子類指針指向父類對象,調用父類的函數,根據對象類型而定義函數,而不是指針類型。
問題:為什么非得繼承?不具有繼承關系的可以嗎?如果不可以那么為什么不可以?
?
?
?
?
?
?
?
?
?
?
==================繼承前(下面的父子類其實并無繼承關系)==================
基類指針和子類指針結構:
?
把指向子類對象的指針強轉為父類指針之后(pBase?=?(Base?*)pDrived;)
?
觀察pBase的變化
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
=================繼承后(下面的父子類有了真實的繼承關系)=================
基類指針和子類指針結構:
?
把指向子類對象的指針強轉為父類指針之后(pBase?=?(Base?*)pDrived;)
?
?
?
?
?
?
?
?
?
?
?
?
//?VirtualFunction.cpp?:?定義控制臺應用程序的入口點。
//
?
#include?"stdafx.h"
#include?<stdio.h>
?
/類Base/
class?Base
{
//測試默認訪問權限
int?test;
?
public:
char?m_char[20];
int?m_int;
?
public:
Base();
virtual?~Base();
?
public:
void?funBase1();
void?funBase2();
void?funBase3();
?
virtual?void?commonFun();
};
?
Base::Base()
{
m_int?=?0x11223344;
strcpy(m_char,?"123456781234567");
}
Base::~Base()
{
}
?
void?Base::funBase1()
{
printf("funBase1\n");
}
void?Base::funBase2()
{
printf("funBase2\n");
}
void?Base::funBase3()
{
printf("funBase3\n");
}
void?Base::commonFun()
{
printf("commonFun?in?Base\n");
}
class?Base2
{
public:
Base2(){};
virtual?~Base2(){};
?
public:
//virtual?void?commonFun();
};
//?void?Base2::commonFun()
//?{
//?//printf("commonFun?in?Base2");
//?}
///類Drived/
class?Drived?:?public?Base,?public?Base2
{
public:
int?m_int;
public:
Drived(){};
virtual?~Drived(){};
?
virtual?void?drivedFun1();
virtual?void?commonFun();
};
?
void?Drived::drivedFun1()
{
printf("drivedFun1\n");
}
void?Drived::commonFun()
{
printf("commonFun?in?Drived\n");
}
?
int?_tmain(int?argc,?_TCHAR*?argv[])
{
?
//?printf("成員變量m_char的地址:%p\n",&Base::m_char);
//?printf("成員變量m_int的地址:%p\n",&Base::m_int);
//?
//?printf("成員函數funBase1的地址:%p\n",&Base::funBase1);
//?printf("成員函數funBase2的地址:%p\n",&Base::funBase2);
//?printf("成員函數funBase3的地址:%p\n",&Base::funBase3);
?
Base?b;
Base?*pBase?=?(Base?*)&b;
?
Drived?d;
Drived?*pDrived?=?(Drived?*)&d;
?
//?pBase?=?(Base?*)pDrived;
//?pBase->commonFun();
?
pBase?=?(Base?*)pDrived;
pBase->drivedFun1();
?
return?0;
}
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的C++虚函数---我的理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VC 编译器的C++关键字 __supe
- 下一篇: OSI七层网络模型与TCP/IP四层网络