C++物件模型之五 構造 析構 賦值筆記 (轉)
C++模型之五 構造 析構 賦值筆記:namespace prefix = o ns = "urn:schemas--com::office" />
1 無繼承下的構造
用C++來編譯
typedef struct
{
float x,y,z;
} point
會宣告一個:無效的預設構造,無效的析構,無效的複製,無效的賦值操作。然而並不實現它們。
當寫成類時體積並沒有改變
class point
{
public:
point (flaot x=0.0,float y = 0.0, float z = 0.0):_x(x),_y(y),_z(z){}
//沒有構造,析構,複製
private:
float _x, _y, _z;
};
明顯初始化列表帶來的三項缺點
1. 只有當類成員都是public時,才有效。
2. 只能指定常量,因為它們在編譯時期可以被評估求值
3. 由於編譯器並沒有自動化施行之,所以初始化行為的失敗可能性會比較高
2 為繼承做準備
class point
{
public:
point (flaot x=0.0,float y = 0.0):_x(x),_y(y){}
//沒有構造,析構,複製
virtual float z();
private:
float _x, _y;
};
體積因有了vtbl所以多vptr 4個位元組的空間。
1 構造被附加了些程式碼以便初始化vptr.被加在基類建構函式之後,員寫的程式碼之前,可能是
point * point ::point( point *this,float x,flaot y):_x(x),_y(y)
{
this->_vptr_point = _vtbl_point; //初始化vptr
this->_x = x; //擴充套件成員初始化列表
this->_y = y;
return this;
}
2 合成一個複製函式和一個複製賦值操作
inline point * point::point ( point *this, const point &rhs)
{
this->_vptr_point = _vtbl_point ;
return this;
}
賦值操作採用位複製技術。
繼承體系下的構造
一般而言編譯器所做的擴充操作大約如下
1. 記錄在成員初始化列表中的資料成員,初始化操作會被放進建構函式本身,以宣告為序。
2. 如果有個成員沒有出現在初始化列表之中,但它有個預設建構函式,將被呼叫。
3. 如果類物件中有vptr它將被設定初始值,指向vbtl。
4. 所有上一層基類構造必須被呼叫,以宣告為序。
1. 如果基類被放在初始化列表中,那麼任何明確指定的引數都應該傳遞過去。
2. 如果基類沒有被放在初始化列表中,而它有個預設建構函式將被呼叫。
3. 如果基類是多重繼承下的第二或後繼的基類,那麼this指標必須調整。
5. 所有虛基類建構函式必須呼叫,從左到右,從最深到最淺:
1. 如果類被放在初始化列表中,那麼引數將傳過去,沒有放在,而類有構造將呼叫。
2. 此外,類中的每個虛基類子物件的偏移量必須在期可被存取。
3. 如果基類是最底層的類,其構造可能被呼叫,某些機制將會放進來。
class point
{
public:
point (flaot x=0.0,float y = 0.0)
point (const point &);
point & operator = (const point &);
virtual ~point();
virtual float z(){return 0.0;}
private:
float _x, _y;
};
3虛繼承下
class point3d:public virtual point
{
public:
point3d ( float x = 0.0, float y=0.0, float z =0.0):point (x,y),_z(z){}
point3d( const poin3d& rhs):point(rhs),_z(rhs.z){}
~point3d();
point3d & operator = (const point3d &);
virtual float z() {return _z;}
protected:
float _z;
};
下面就是point3d的建構函式被擴充的內容
point3d *point3d::point3d( piont3d *this ,bool _most_derived,float x, float y, float z)
{
if ( _most_derived != false) //在C++中虛基類的建構函式由最底層的類負責呼叫,所以要判斷自己有沒有派this->point::point(x,y); //所以要判斷自己有沒有派生類
this->_vptr_point3d = _vtbl_point3d; // 初始化自己的vptr
this->vptr_point3d_point = _vtbl_point3d_point; //初始化基類的vptr
this->_z = rhs.z;
return this;
}
4vptr初始化
class Vertex:virtual public point{….};
class Vertex3d:public point3d,public Vertex {…..};
class Pvertex:public Vertex3d{….};
它們中都有個virtual size()
構造呼叫順序是:由根源而末端,由內而外。在建構函式中呼叫虛擬函式被評估為本類的函式而不是派生類的,多型特性在物件構造中無效。
1. 在派生類中所有的虛基類及上一層基類的建構函式被呼叫。
2. 上述完成後物件的vptr被初始化,指向vbtl
3. 如果有成員初始化列表的話,將在構造內展開,必須在vptr被設定後進行
4. 最後執行程式設計師提供的程式碼。
Pvertex ::Pvertex ( float x, float y, float z):_next(0),Vertex3d(x,y,z),point(x,y)
{
if (spyOn)
cerr<
}
被擴充為:
Pvertex *Pvertex::Pvertex( Pvertex *this ,bool _most_derived, float x, float,y,float z)
{
if ( _most_derived != false)
this->point::point(x,y);
this->vertex3d::vertex3d(x,y,z);
this->_vptr_Pvertex = _vtbl_Pvertex;
this->_vptr_point_Pvertex = _vbtl_point_Pvertex;
if ( spyOn)
cerr<_vptr_Pvertex[3].faddr)(this)< return this; } 物件賦值 賦值操作將在以下情況下需要 1. 當類內帶有一個物件成員,而其類有個賦值操作。 2. 當本類的基類有個賦值操作時。 3. 當本類宣告瞭任何虛擬函式。 4. 當本類繼承自一個虛繼承類時,無論基類是否有賦值操作。 Inline point & point::operator = ( const point &p) { _x = p._x; _y=p._y; return this; } class point3d :: virtual public point {…..} 編譯器將為point3d合成一個賦值操作 inline point3d & point3d::operator = (point3d *const this,const point3d &p) { this->point::operator=(p); _z=p._z; return *this; } 因為C++標準沒有賦值列表,所以造成派生類賦值操作中將會重複呼叫基類的賦值操作 inline vertex3d& vertex3d::operator=(const vertex3d &v) { this->point::operator=(v); this->point3d::operator=(v); //內含有this->point::operator=(v); this->vertex::operator=(v); //內含有this->point::operator=(v); return this; } 建議儘可能不要允一個虛基類的賦值操作,不要在任何虛基類中宣告資料。 物件功能 測試物件的構造和賦值操作成本 struct point3d {float x,y,z;}; class point3d {public : float x,y,z;}; 未最佳化 結構體 5.84 7.22 內聯構造逐位 6.00 7.33 內聯構造帶虛擬函式非逐位 7.67 13.05 單一繼承內聯逐位 6.26 7.33 單一繼承內聯非逐位 10.35 17.74 單一虛繼承內聯非逐位 17.29 23.93 多重繼承內聯逐位 6.26 7.33 多重繼承內聯非逐位 12.39 20.39 多重虛繼承內聯非逐位 19.31 26.80 析構 如果類沒有定義解構函式,那麼只有在類內帶的物件成員並且物件成員有析構或者基類擁有析構的情況下,編譯器才會自動合成出一個來,否則是不需要的。 class point { public: point (float x = 0.0 ,float y=0.0); point (const point &); virtual float z(); …. Private : Float _x,_y; }; 既是類point擁有虛擬函式,編譯器也不會合成一個解構函式。既是類lines資料成員是point beging,end; 也沒有必要因為point本身沒有解構函式。 你應該拒絕被稱為對稱策略的想法:“你已經定義了構造就必須定義個析構”。 決定為類是否在程式層面提供解構函式要看: 類物件生命在哪裡結束?需要什麼操作才能保證物件的完整性。這也是構造和解構函式什麼時候起關鍵作用。 Main() { point pt; point *p=new point3d; foo( &pt,p); …. Delete p; } pt和p在函式foo()前要初始化,否則使用者必須明確提供座標,一般而言類的使用者這沒有辦法檢驗一個本地變數或者堆變數是否已經初始化了,所以這時建構函式工作是有必要的。同樣在delete p之前對p是否要進行處理保證物件的完整性 比如:p->x=0;p->y=0; 目前對於析構的一種最佳策略就是維護兩份析構實體 1 一個完整物件實體,總是設定好vptrs,並呼叫虛基類解構函式。 2 一個基類子物件實體,除非在解構函式中呼叫一個虛擬函式,否則不會去呼叫虛基類的解構函式並設定vptr 一個物件的生命結束於其解構函式開始執行之前時,由於每個基類解構函式都輪番被呼叫,所以派生類實際上變成一個完整的物件。如Pvertex物件歸還空間時,會依次變為一個Vertex3d,Vertex,Point3d,Point. 析構順序: 1 解構函式本身首先執行 2 如果類有成員物件,而後者擁有解構函式,那麼它們會以宣告的順序相反的順序呼叫。 3 如果物件帶有個vptr,則現在被重新設定,指向適當的基類vtbl. 4 如果有任何直接上一層非虛基類擁有解構函式,那麼它們會以宣告的順序相反的順序呼叫。 5 如果有任何虛基類擁有解構函式,並且時最尾端的類,那麼它們會以原來的順序相反的順序呼叫。 曾牧暗鯊,網名:大白鯊 -8-16
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-982171/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 《Effective C++》第2章 構造/析構/賦值運算(2)-讀書筆記C++賦值筆記
- 《Effective C++》第2章 構造/析構/賦值運算(1)-讀書筆記C++賦值筆記
- 《EffectiveC++》讀書筆記之二構造/析構/賦值運算C++筆記賦值
- 《Effective C++》閱讀總結(二):類的構造、析構和賦值C++賦值
- C++物件模型之二 構造語句 (轉)C++物件模型
- ES6學習筆記(五)【解構賦值,Iterator】筆記賦值
- C++之this指標、拷貝構造、賦值構造、單列模式(餓漢模式、懶漢模式)C++指標賦值模式
- C++物件模型之六 執行期筆記 (轉)C++物件模型筆記
- C++之Big Three:拷貝構造、拷貝賦值、解構函式探究C++賦值函式
- JavaScript 物件解構賦值JavaScript物件賦值
- 《Effective C++》第三版-2. 構造析構賦值運算(Constructors,Destructors,and Assignment Operators)C++賦值Struct
- C++物件模型之七 模板 異常 RTTI筆記 (轉)C++物件模型筆記
- 區分copy構造與copy賦值賦值
- 【C++】 46_繼承中的構造與析構C++繼承
- c++ set容器 —構造 賦值 大小 交換 插入 刪除 程式碼示例C++賦值
- C++記憶體分配與物件構造的分離C++記憶體物件
- 構造做題筆記筆記
- ES6之解構賦值賦值
- ES6語法學習筆記之let const 解構賦值筆記賦值
- JavaScript ECMAScript 6 筆記 -2 《變數的解構賦值》JavaScript筆記變數賦值
- 解構賦值賦值
- 物件賦值轉換物件賦值
- Effective c++(筆記) 中關於建構函式、解構函式以及賦值操作符的知識C++筆記函式賦值
- ES6學習筆記二(變數結構賦值)筆記變數賦值
- JS解構賦值JS賦值
- C#例項構造器,型別構造器 -筆記型別筆記
- 深入分析C++物件模型之移動建構函式C++物件模型函式
- 2020-10-18C++筆記之C/C++之字串賦值C++筆記字串賦值
- php之普通變數賦值、物件賦值、引用賦值的區別PHP變數賦值物件
- 《深度探索C++物件模型》讀書筆記C++物件模型筆記
- C++ 構造方法C++構造方法
- 物件導向程式設計(C++篇3)——析構物件程式設計C++
- Javascript 解構賦值,將屬性/值從物件/陣列中取出,賦值給其他變數JavaScript賦值物件陣列變數
- 十七、物件的構造物件
- JavaScript 字串解構賦值JavaScript字串賦值
- 物件導向程式設計(C++篇2)——構造物件程式設計C++
- C++:String物件的構造及深拷貝C++物件
- es6學習筆記整理(一)變數宣告、解構賦值筆記變數賦值