1.對象模型
C++對象模型中,non static數據成員被放置到對象內部,static數據成員,static and non static函數成員均被放到對象之外。
而對于虛函數的支持則分兩步完成:
1.每一個class產生一堆指向虛函數的指針,放在表格之中。這個表格稱之為虛函數表(virtual table,vtbl)。
2.每一個對象被添加了一個指針,指向相關的虛函數表vtbl。通常這個指針被稱為vptr。vptr的設定(setting)和重置(resetting)都由每一個class的構造函數,析構函數和拷貝賦值運算符自動完成。
例如圖1中,由于A類中有虛函數,所以A類的對象中有自己的兩個成員變量m_data1、m_date2和一個指向vtbl的指針(vptr)。B類是A類的子類,B類對象除了有父類對象所有成員和vptr外,還有自己的成員m_data3。這些對象占用內存的大小由它們的成員變量和vptr指針決定,在不同的編譯環境下它們的內存大小會有所不同。
2.const
當類中成員函數的const和non-const版本同時存在時,const對象只會調用const版本,non-const對象只會調用non-const版本。
const對象和non-const對象都可以調用const成員函數;
non-const對象可以調用non-const成員函數而const對象則不可以。
例如以下程序:
#include <iostream>
class Foo
{
public:
Foo(int id) : id_(id) { }
void print() const {
std::cout<<"const print id:"<<id_<<std::endl;
}
void print() {
std::cout<<"non-const print id:"<<id_<<std::endl;
}
void say() {
std::cout<<"say id:"<<id_<<std::endl;
}
void tell() const {
std::cout<<"tell id:"<<id_<<std::endl;
}
private:
int id_;
};
int main()
{
Foo a1 = Foo(6);
const Foo a2 = Foo(5);
a1.print();
a2.print();
a1.say();
a1.tell();
//a2.say(); //[Error] passing 'const Foo' as 'this' argument of 'void Foo::say()' discards qualifiers [-fpermissive]
return 0;
}
例中print函數同時有const和non-const版本,const對象和non-const對象都能調用對應的版本。而const對象調用non-const成員函數時編譯會出錯。
3.重載new和delete
C++中new,delete,new[],delete[]是可以重載的,這樣可以在程序執行new或delete時另外地實現我們自己所想要的操作。
new,delete,new[],delete[]的重載分為全局重載和對特定類的重載。
例如:
全局重載
//global operator new/delete
void* myAlloc(size_t size){
return malloc(size);
}
void myFree(void* ptr){
return free(ptr);
}
inline void* operator new(size_t size){
std::cout<<"global new() \n";
return myAlloc(size);
}
inline void operator delete(void* ptr){
std::cout<<"global delete() \n";
return myFree(ptr);
}
對A類對象new,delete的重載
class A {
int id;
public:
A(int i):id(i){
std::cout<<"A構造 \n";
}
~A(){
std::cout<<"A析構 \n";
}
static void* operator new(size_t size);
static void operator delete(void* pdead,size_t size);
};
//member operator new/delete
void* A::operator new(size_t size) {
A* p = (A*)malloc(size);
std::cout<<...........;
return p;
}
void A::operator delete(void* pdead,size_t size) {
std::cout<<...........;
free(pdead);
}