C++ function機制

C++在佈局以及時間上的主要額外負擔是有virtual引發的。
1. 虛函數機制(virtual function):用於支持執行期綁定
2. 虛繼承(virtual base class): 用於出如今繼承體系中的多個baseclass,有一個單一而被共享的實體。


C++支持3中成員函數: 
static member function
nonstatic member function
virtual memeber function


Nonstatic member function(非靜態成員函數)
C++的設計準則:非靜態成員函數和非成員函數具備相同的效率。其實編譯器在編譯時,將成員函數實體轉換成對等的非成員函數實體,這也是爲何在調用成員函數時,會傳遞this指針了。

好比非成員函數以下:
float compute3d(const Point3d *_this)
{
        return sqrt( _this->x * _this->x +
                     _this->y * _this->y +
                     _this->z * _this->z);
}



使用的時候傳入對象指針,經過對象指針獲取成員。若是是成員函數,多是這樣的。
float compute3d()
{
    return sqrt(x * x + y * y + z *z);
}



可是在真正調用的時候,實際上是通過轉化的。
1. 改寫函數的signature(函數原型) ,用來安插一個額外的參數到成員函數中,提供存取對象屬性的渠道,即this指針。
float compute3d(Point3d * const this)

2. 將對每個對非靜態的屬性的存取操做改成由this指針來操做,即將
return sqrt(x * x + y * y + z *z)改成
 return sqrt( this->x * this->x +
                   this->y * this->y +
                   this->z * this->z);

3. 將成員函數從新寫爲外部函數,對函數名稱進行"nabgkubg"處理,時期成爲獨一無二的詞彙。
extern compute3d_8Point3dFv(register Point3d *const this);

那對象會對象指針在調用時即發生以下變化:
obj.compute3d();------------------compute3d_8Point3dFv(&obj);
p->compute3d();------------------compute3d_8Point3dFv(p);
(obj爲對象,p爲對象指針)



virtual member function(虛擬成員函數)

C++中的虛函數的做用主要是實現了多態的機制。多態就是用父指針指向子類 對象,而後經過父類的指針調用實際子類的成員函數。ios

// virtualFunTest.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#include <iostream>

using namespace std;

class Base
{		
	public:
				virtual void f()
				{
					cout<<"Base: f()"<<endl;
				};

				virtual void g()
				{
					cout<<"Base: g()"<<endl;
				};
				
				virtual void h()
				{
					cout<<"Base: h()"<<endl;
				};
};


class Derive1 : public Base
{
	public:	
				virtual void f()
					{
						cout<<"Derive1: f()"<<endl;
					};

					virtual void g1()
					{
						cout<<"Derive1: g1()"<<endl;
					};

					virtual void h1()
					{
						cout<<"Derive1: h1()"<<endl;
					};
};

void Test1()
{
			Base b;
			typedef void(*Fun)(void);
			Fun pFun = NULL;

			//int*(&b) 虛函數表指針
			cout<<"對象其實地址: "<<&b<<endl;
			cout << "虛函數表地址:" << (int*)(&b) << endl;

			//*(int*)(&b) 指虛函數表  (int*)*(int*)(&b)表示虛函數表的第一個內容
			//能夠理解(int*)*(int*)(&b)+0  (int*)*(int*)(&b)爲數組首地址
			
			// Invoke the first virtual function
			pFun = (Fun)*((int*)*(int*)(&b)+0); // Base::f()	
			cout << "虛函數表 — 第一個函數地址:" << (int*)*(int*)(&b) << endl;
			
			pFun();

			pFun= (Fun)*((int*)*(int*)(&b)+1); // Base::g()	
			cout << "虛函數表 — 第二個函數地址:" << (int*)*(int*)(&b) + 1<< endl;

			pFun();

			pFun=(Fun)*((int*)*(int*)(&b)+2); // Base::h()
			cout << "虛函數表 — 第三個函數地址:" << (int*)*(int*)(&b) + 2<< endl;

			pFun();
}

void Test2()
{
			Base *p = new Derive1();
		    typedef void(*Fun)(void);
			Fun pFun = NULL;

			//int*(&b) 虛函數表指針
			cout<<"對象其實地址: "<<p<<endl;
			cout << "虛函數表地址:" << (int*)p<< endl;
			
			
			pFun = (Fun)*((int*)*(int*)p+0); 
			cout << "虛函數表 — 第一個函數地址:" <<(int*)*(int*)p<< endl;			
			pFun();

			pFun=  (Fun)*((int*)*(int*)p+1); 
			cout << "虛函數表 — 第二個函數地址:" <<(int*)*(int*)p+1<< endl;
			pFun();

			pFun=(Fun)*((int*)*(int*)p+2); 
			cout << "虛函數表 — 第三個函數地址:" << (int*)*(int*)p+2<< endl;
			pFun();

			pFun= (Fun)*((int*)*(int*)p+3); 
			cout << "虛函數表 — 第四個函數地址:" << (int*)*(int*)p+3<< endl;
			pFun();

			pFun= (Fun)*((int*)*(int*)p+4); 
			cout << "虛函數表 — 第五個函數地址:" << (int*)*(int*)p+4<< endl;
			pFun();
}



Test1結果/Test2結果數組


虛函數表中按照順序依次存放了類中定義的虛函數。app



因而可知,在虛函數表中,函數地址的順序爲:函數

Derive1:f() , Base:g(), Base:h(), Derive1:g1(), Derive1:h1(), 地址由低到高,個人理解是,子類在創建本身的虛函數表時,佈局

首先將父類的虛函數表內容拷貝過來,而後檢查其中的函數有沒有被覆蓋,若是有覆蓋,替換掉,而後把其餘新添加的虛函數按照順序依次添加到虛函數表中。this

此處沒有探討多重繼承的狀況。spa



C++靜態成員函數和靜態成員設計

靜態成員變量:每個對象都共享一個變量,static成員是獨立於類的任意對象而存在的;每一個static成員是與類關聯的,和該類的對象無關。3d

 靜態成員函數:靜態成員函數能夠直接訪問靜態成員變量,若是要訪問非靜態成員變量的話,只能訪問某一個對象的非靜態成員變量和靜態成員函數。能夠傳一個對象的指針,引用等參數給這個靜態成員函數。指針

class Account
{
   	public:
	void applyint()
	{
		amount += amount * interestRate;		
	}

	static double rate()
	{
		return interestRate;
	}

	static void rate(double); //sets a new rate

	private:
	std::string owner;
	double amount;
	static double interestRate;
	static double initRate();
}

該類時一個銀行帳戶類,不一樣的帳戶對應不一樣的客戶,可是利率是同樣的。獨立於具體客戶對象的,全部interestRate爲靜態成員。

靜態成員的訪問。經過對象,對象指針以及類名加做用域操做符在訪問。

Account ac1;
Account *ac2 = &ac1;

double rate;
rate = ac1.rate();
rate = ac2->rate();
rate = Account::rate();

普通的成員函數訪問靜態成員時,無需做用域操做符,能夠直接訪問,好比applyinit方法。

static data member存放於程序的data segment(數據段)中

static成員函數

在類外部定義類的靜態成員函數時,無需static關鍵字,在聲明處有static便可。

static成員是類的組成部分,但不是對象的組成部分,全部是不會像static成員函數傳遞this指針的。

static成員函數不能聲明爲const。由於成員函數被const修飾後表示不會修改對象得屬性,可是靜態成員函數不屬於對象。

相關文章
相關標籤/搜索