本周主要講了三種類跟類的關(guān)系,包括復(fù)合,委托,以及繼承
1.復(fù)合
1.1定義
在一個類中以另一個類的對象作為數(shù)據(jù)成員的,稱為類的復(fù)合(composition)。
例如以下代碼
template<class T>
class queue{
...
protected:
deque<T> c;
public:
some code
}
上述代碼表示,類queue中有個成員是類duque對象,這種情況即為復(fù)合,同時deque的功能要比queue要來的多,在some code中,queue的實現(xiàn)則可以直接調(diào)用deque的實現(xiàn),這種情況稱之為adapter。
1.2內(nèi)存布局
#include<iostream>
using namespace std;
class A
{
int i;
int j;
};
class B
{
A a;
int k;
};
int main()
{
cout<<"A size is "<<sizeof(A)<<endl;
cout<<"B size is "<<sizeof(B)<<endl;
return 1;
}
運行結(jié)果如下:
從結(jié)果可以很明顯看出,B的大小包括對象a的大小加上自身的一個int
1.3構(gòu)造與析構(gòu)
#include<iostream>
using namespace std;
class A
{
int i;
int j;
public:
A(){cout<<"A ctor"<<endl;}
~A(){cout<<"A dtor"<<endl;}
};
class B
{
A a;
int k;
public:
B(){cout<<"B ctor"<<endl;}
~B(){cout<<"B dtor"<<endl;}
};
int main()
{
B b;
return 1;
}
運行結(jié)果如下:
首先調(diào)用了類A的構(gòu)造函數(shù),然后調(diào)用B自身的構(gòu)造函數(shù),析構(gòu)函數(shù)過程則相反,即 構(gòu)造由內(nèi)而外,析構(gòu)由外而內(nèi)
2.委托
2.1 定義
擁有其他類的指針,用指針相連,與復(fù)合不同的是,生存期不同步,復(fù)合同時構(gòu)造同時消亡,委托則是在有需要時在創(chuàng)建。如下所示
classStringRep;
classString{
public:
...
private:
StringRep* rep; //里面包含了指向StringRep類的指針;
}
classStringRep{
...
}
2.2 pimpl(pointer to implication)
pimpl的作用是將實現(xiàn)與對外接口分開,分為如下兩個部分
Handle:表示對外的接口,即上述String類中的內(nèi)容;
Body:表示具體的實現(xiàn),實現(xiàn)則在StringRep類中實現(xiàn);
Body的怎么變化不影響Handle;Handle怎么修改,Body無需重新編譯,也叫編譯防火墻;
上述例子通過引用計數(shù)來共享內(nèi)存,當(dāng)所指字符串內(nèi)容一致時,指針指向同一塊內(nèi)存,同時記錄下指向這片內(nèi)存的指針數(shù)量,如果有指針需要修改內(nèi)容,則創(chuàng)建一個副本進(jìn)行修改,同時指向該內(nèi)存的指針數(shù)量減一。
3.繼承,表示is-a
3.1聲明格式
class 派生類名:繼承方式(若不具體指出默認(rèn)為private) 基類名{ …};
內(nèi)存分布
#include<iostream>
using namespace std;
class A
{
int i;
int j;
};
class B:public A
{
int k;
};
int main()
{
cout<<"A size is "<<sizeof(A)<<endl;
cout<<"B size is "<<sizeof(B)<<endl;
return 1;
}
運行結(jié)果如下:
這種單繼承以及沒有虛函數(shù)的情況下,內(nèi)存分布和構(gòu)造析構(gòu)順序都與復(fù)合類似,都是構(gòu)造由內(nèi)而外,析構(gòu)由外而內(nèi),派生類的大小則是基類大小加上private成員中的non static data。
4.虛函數(shù)與多態(tài)
非虛函數(shù):不希望派生類重新定義它
虛函數(shù):希望派生類重新定義它,且對它已有默認(rèn)定義
純虛函數(shù):你希望派生類一定要重新定義它,你對他沒有默認(rèn)定義
classShape{
public:
virtual void draw()const=0; //purevirtual必須被所有子類重新定義;
virtual void error(const std::string& msg); //impurevirtual此處為默認(rèn)定義,允許子類去重新定義;
int objectID() const; //non-virtual不可被子類重新定義
}
class Rectangle:public Shape{...};
class Ellipse:public Shape{...};