由于這周出差,暫時(shí)未有時(shí)間寫筆記,故引用下午戴涝。出差回來補(bǔ)上。謝謝。
參考資料:http://blog.csdn.net/ns708865818/article/details/50740372
內(nèi)容大綱
1.對象模型
2.const
3.new & delete
這一周主要內(nèi)容是講對象模型啥刻,其余內(nèi)容是作為之前課程內(nèi)容的補(bǔ)充奸鸯,所以本文將主要著重講解對象模型。
關(guān)于具體的對象模型的分析可以看這里可帽,這里只對一些課堂中提到的概念做一些記錄和分析娄涩。
1.對象模型
1.1vptr虛指針
1.c++類中的重載
看看下面的代碼:
#include <iostream>
using namespace std;
class Vehicle
{
public:
Vehicle(float speed,int total)
{
Vehicle::speed=speed;
Vehicle::total=total;
}
void ShowMember()
{
cout<<speed<<"|"<<total<<endl;
}
protected:
float speed;
int total;
};
class Car:public Vehicle
{
public:
Car(int aird,float speed,inttotal):Vehicle(speed,total)
{
Car::aird=aird;
}
void ShowMember()
{
cout<<speed<<"|"<<total<<"|"<<aird<<endl;
}
protected:
int aird;
};
void main()
{
Vehicle a(120,4);
a.ShowMember();
Car b(180,110,4);
b.ShowMember();
cin.get();
}
#include <iostream>
using namespace std;
class Vehicle
{
public:
Vehicle(float speed,int total)
{
Vehicle::speed=speed;
Vehicle::total=total;
}
void ShowMember()
{
cout<<speed<<"|"<<total<<endl;
}
protected:
float speed;
int total;
};
class Car:public Vehicle
{
public:
Car(int aird,float speed,inttotal):Vehicle(speed,total)
{
Car::aird=aird;
}
void ShowMember()
{
cout<<speed<<"|"<<total<<"|"<<aird<<endl;
}
protected:
int aird;
};
void main()
{
Vehicle a(120,4);
a.ShowMember();
Car b(180,110,4);
b.ShowMember();
cin.get();
}
在c++中是允許派生類重載基類成員函數(shù)的,對于不同類的對象映跟,調(diào)用其類的成員函數(shù)的時(shí)候蓄拣,系統(tǒng)是知道如何找到其類的同名成員。上面代碼中的a.ShowMember()調(diào)用的是Vehicle::ShowMember()努隙,而b.ShowMember()調(diào)用的是Car::ShowMemeber()球恤。
#include <iostream>
using namespace std;
class Vehicle
{
public:
Vehicle(float speed,int total)
{
Vehicle::speed=speed;
Vehicle::total=total;
}
void ShowMember()
{
cout<<speed<<"|"<<total<<endl;
}
protected:
float speed;
int total;
};
class Car:public Vehicle
{
public:
Car(int aird,float speed,inttotal):Vehicle(speed,total)
{
Car::aird=aird;
}
void ShowMember()
{
cout<<speed<<"|"<<total<<"|"<<aird<<endl;
}
protected:
int aird;
};
void test(Vehicle &temp)
{
temp.ShowMember();
}
void main()
{
Vehicle a(120,4);
Car b(180,110,4);
test(a);
test(b);
cin.get();
}
Car::ShowMemeber()。
#include <iostream>
using namespace std;
class Vehicle
{
public:
Vehicle(float speed,int total)
{
Vehicle::speed=speed;
Vehicle::total=total;
}
void ShowMember()
{
cout<<speed<<"|"<<total<<endl;
}
protected:
float speed;
int total;
};
class Car:public Vehicle
{
public:
Car(int aird,float speed,inttotal):Vehicle(speed,total)
{
Car::aird=aird;
}
void ShowMember()
{
cout<<speed<<"|"<<total<<"|"<<aird<<endl;
}
protected:
int aird;
};
void test(Vehicle &temp)
{
temp.ShowMember();
}
void main()
{
Vehicle a(120,4);
Car b(180,110,4);
test(a);
test(b);
cin.get();
}
對象a與b分辨是基類和派生類的對象荸镊,而函數(shù)test的形參卻只是Vehicle類的引用咽斧,按照類繼承的特點(diǎn),系統(tǒng)把Car類對象看做是一個(gè) Vehicle類對象贷洲,因?yàn)镃ar類的覆蓋范圍包含Vehicle類收厨,所以test函數(shù)的定義并沒有錯(cuò)誤,我們想利用test函數(shù)達(dá)到的目的是优构,傳遞不同類對象的引用诵叁,分別調(diào)用不同類的,重載了的,ShowMember成員函數(shù),但是程序的運(yùn)行結(jié)果卻出乎人們的意料钦椭,系統(tǒng)分不清楚傳遞過來的基類對象還是派生類對象拧额,無論是基類對象還是派生類對象調(diào)用的都是基類的ShowMember成員函數(shù)。
解決上面這個(gè)問題就是利用多態(tài)了彪腔。
2.多態(tài)中的虛表與虛地址
對C++ 了解的人都應(yīng)該知道虛函數(shù)(Virtual Function)是通過一張?zhí)摵瘮?shù)表(Virtual Table)來實(shí)現(xiàn)的侥锦。簡稱為V-Table。在這個(gè)表中德挣,主是要一個(gè)類的虛函數(shù)的地址表恭垦,這張表解決了繼承、覆蓋的問題格嗅,保證其容真實(shí)反應(yīng)實(shí)際的函數(shù)番挺。
class A
{
protected:
virtual voidtest(){cout<<"aaa"<<endl;}
virtual voidtest1(){cout<<"df"<<endl;}
};
(1)sizeof(A)=4,這個(gè)4應(yīng)該是個(gè)指針大小,代表虛指針屯掖,虛指針是個(gè)函數(shù)指針玄柏,指向虛函數(shù)表里面的位置,虛表里面存放的是虛函數(shù)的地址贴铜。
(2)A a;sizeof(a)=4粪摘,虛指針存在于每個(gè)對象中瀑晒,因?yàn)轭惒皇且粋€(gè)可以存儲的地方。
(3)C++的編譯器應(yīng)該是保證虛函數(shù)表的指針存在于對象實(shí)例中最前面的位置(這是為了保證取到虛函數(shù)表的有最高的性能——如果有多層繼承或是多重繼承的情況下)徘意。 這意味著我們通過對象實(shí)例的地址得到這張?zhí)摵瘮?shù)表苔悦,然后就可以遍歷其中函數(shù)指針,并調(diào)用相應(yīng)的函數(shù)映砖。
(4)虛表是整個(gè)類共用的,他的大小取決于你定義的虛函數(shù)的個(gè)數(shù),以及編譯器的策略.一般存在于內(nèi)存的某個(gè)地方,你不需要去管他间坐。
這里我還有一個(gè)問題,為什么下面這個(gè)程序等于1:
class a
{
protected:
voidtest(){cout<<"aaa"<<endl;}
voidtest1(){cout<<"df"<<endl;}
};
int main()
{
cout<<sizeof(a)<<endl;
getchar();
}
class a
{
protected:
voidtest(){cout<<"aaa"<<endl;}
voidtest1(){cout<<"df"<<endl;}
};
int main()
{
cout<<sizeof(a)<<endl;
getchar();
}
3.虛函數(shù)表
(1)如何獲取虛函數(shù)表的地址
假設(shè)我們有這樣的一個(gè)類:
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 Base {
public:
virtual void f() { cout <<"Base::f" << endl; }
virtual void g() { cout <<"Base::g" << endl; }
virtual void h() { cout <<"Base::h" << endl; }
};
按照上面的說法邑退,我們可以通過Base的實(shí)例來得到虛函數(shù)表竹宋。 下面是實(shí)際例程:
typedef void(*Fun)(void);
Base b;
Fun pFun = NULL;
cout << "虛函數(shù)表地址:" << (int*)(&b) << endl;
cout << "虛函數(shù)表 — 第一個(gè)函數(shù)地址:" << (int*)*(int*)(&b)<< endl;
// Invoke the first virtualfunction
pFun = (Fun)*((int*)*(int*)(&b));
pFun();
typedef void(*Fun)(void);
Base b;
Fun pFun = NULL;
cout << "虛函數(shù)表地址:" << (int*)(&b) << endl;
cout << "虛函數(shù)表 — 第一個(gè)函數(shù)地址:" << (int*)*(int*)(&b)<< endl;
// Invoke the first virtualfunction
pFun = (Fun)*((int*)*(int*)(&b));
pFun();
實(shí)際運(yùn)行經(jīng)果如下:(Windows XP+VS2003, Linux 2.6.22 + GCC 4.1.3)
虛函數(shù)表地址:0012FED4
虛函數(shù)表 — 第一個(gè)函數(shù)地址:0044F148
Base::f
通過這個(gè)示例,我們可以看到地技,我們可以通過強(qiáng)行把&b轉(zhuǎn)成int 蜈七,取得虛函數(shù)表的地址,然后莫矗,再次取址就可以得到第一個(gè)虛函數(shù)的地址了飒硅,也就是Base::f(),這在上面的程序中得到了驗(yàn)證(把int強(qiáng)制轉(zhuǎn)成了函數(shù)指針)作谚。通過這個(gè)示例三娩,我們就可以知道如果要調(diào)用Base::g()和Base::h(),其代碼如下:
(Fun)*((int*)*(int*)(&b)+0); //Base::f()
(Fun)*((int*)*(int*)(&b)+1); // Base::g()
(Fun)*((int*)*(int*)(&b)+2); // Base::h()