- 同class 的 obj 互爲friend
- 傳參和返回儘可能引用
- 返回時若是是臨時變量不能引用
- 加減乘除負號不能返回引用,正號能夠
- 傳遞者(return, 實參) 無需知道 接受者(函數返回類型,形參)是否是接受的引用
- 儘可能const(類方法,傳參等)
- 構造函數儘可能初始化賦值不要經過{}賦值
c3+=c2+=c1
從右往左,operator +=
若是返回值不是對象或其引用則不能連續- 操做符都是做用於左邊
T pc = new T(a)
的操做c++
void* mem = operator new(sizeof(T))
(實際內部調用malloc(n))pc = static_cast<T*>(mem);
//轉型pc->T:T(a)
//調用構造函數(定義成員,賦值)
delete pc
的操做數組
T::~T(pc)
//析構函數operator delete(pc)
//(實際內部調用free(pc)
new []
要和delete []
對應用函數
- 內存分配會16字節的倍數 (32位和64位都是?)
- 若是沒有對應,好比
T *p = new T[3]; delete p
- 調用
delete p
會釋放申請的動態內存,可是隻會調用一次析構函數(圖是有問題的應該是從下往上析構)- 調用
delete[] p
纔會在釋放動態內存後,正確的調用三次析構函數![]()
- 如上圖,若是不是
new
的數組,會少了從上往下的第二個3內存
- 內存依次記錄的是(16進制):
- 分配的內存大小+1(1表明分配出去的意思,由於分配的大小會是16的倍數,能夠用這一位)
- 若是是數組會記錄數組的大小
- 實際數據
- 同第一個
class Account {
public:
static double m_rate; // 聲明,同時須要在外部定義(應該是編譯器怕致使重複連接 )
static const int x = 2.1; // 常量能夠,也能夠用很是量的方式,可是不能在內外都賦予初始值
static constexpr double d = 1.0; // 編譯器-O0時對於非int char等須要這麼操做
static Account ac; //能夠不在外部定義(在外部定義也OK)
Account ac; // 錯誤類類型成員只能是static
};
double Account::m_rate; //定義(必需要有這一步)
複製代碼
- 模板致使代碼膨脹
- 繼承函數繼承的是調用權
- 委託模式共用引用修改時能夠 copy-on-write (string的實現也是cow)
- 成員函數同時存在const 和 non-const版本時,const obj 只能調用const的,non-const的只能調用non-const的
![]()
- 繼承和組合構造從內而外,析構由外而內,繼承的父類析構必須是
virtual
- 繼承空心三角箭頭頭
- 組合實心菱形箭頭尾
- 委託空心菱形箭頭尾
- T轉換函數 ex:
operator double() const {return xxx;}
把T->double- 同時可使用no-explict的構造函數 ex:
T(double x){}
double->T
Fraction f(3,5);
double d = 4.0+f; // 會先找operator(double, Fration),看看能不能把Fraction轉換成double, 找 operator double()或者non-explict構造函數,可是共存可能會致使二義性
複製代碼
pointer-like classspa
- 特殊的重載符號
operator ->
,重載後不會消耗掉->
;- 迭代器也是一種智能指針
function-like class指針
- 重載
operator ()
- 若是類型是依賴於模板參數的限定名,那麼在它以前必須加
typename
,避免編譯器在實例化時才知道,explain(T::c
不加的話並不知道這個是個嵌套類型仍是靜態成員或者靜態函數) 好比:
template <class T> void foo() {
T::iterator * iter; // 不加typename, 這一行多是個乘法運算多是個定義語句
// ...
}
複製代碼
連接器相關: 咱們須要注意從庫中導入文件的粒度問題:若是某個特定符號的定義是必須的,那麼包含該符號定義的整個目標文件(一個庫可能會有多個目標文件)都要被導入code
有默認值的會編譯不經過(list模板參數有默認值) cdn
![]()
虛函數實例內存多一個虛指針的大小對象