類與對象:
const常量哪怕棧空間數據被改 被訪問時依然是使用存於符號表的數據
構造函數的形式:
拷貝構造 Test(Test &t){}
初始化構造 Test(int d): data(d){}
Test t(10);
t = 200;
//只要類型不同,會創建一箇中間的無名變量來賦值;
//實際上是調用了構造函數中的 Test(200) 創建了一個對象,將對象賦值給t;
//如果構造函數中使用explicit作爲修飾,不能隱式轉化時,會杜絕這種情況發生;
//上一行的情況則必須 使用: t = (Test) 200;
Test t1 = t2; //拷貝構造
Test t1; t1 = t2; //運算符重載賦值
拷貝構造: 形如 void fun(Test a);
如果函數的參數是以傳入對象的形式, 那麼傳入對象的時候會進行一次拷貝構造
返回值是對象的時候: Test fun(int a)
{
Test new_one(a);
return new_one;
}
如果編譯器做了優化 可能會延長返回對象的生存週期 而不是重新拷貝構造一個無名對象來返回
*拷貝構造的時候要考慮淺拷貝和深拷貝的問題
注意: 局部對象不能以引用形式返回,局部對象會被銷燬
*拷貝構造的參數最好使用const修飾 比如Test(const Test &t)(…)
因爲return的時候可能會檢測到拷貝構造函數,而return返回的對象具有常性,需要const屬性
賦值函數的編寫:
1.自身賦值問題
2.釋放原有內存的空間
3.開闢空間深拷貝賦值數據
4.返回自身對象
—- Tip:異常安全問題 在賦值期間發生異常 保證賦值兩者的數據安全
*類成員有指針的時候 考慮拷貝構造和析構還有運算符重載的安全性
vld.h: 檢測內存泄露的庫
Question: C++的類的初始的函數有六個 分別是什麼?
explicit關鍵字的用法?
如何把一個只有一個數據成員的對象直接給一個該數據的變量賦值?(Test t(200); int value = t;)
成員函數中用const修飾的方法:
void Test::fun()const;
實際上相當於
void Test::fun(const Test * const this);
本質上就是不能修改this所指的對象的值;
***tips: 常方法不能調用有可能改變對象的值的成員函數;
成員函數中的static修飾的方法:
static修飾的變量以及函數,被所有對象共享,沒有this指針;
***tips: 靜態方法不能調用成員函數,因爲它是被所有類對象共享的;
用friend關鍵字修飾的友元函數可以訪問私有成員;
— 常用來重載流運算符;
運算符重載:
**不能使用的重載運算符:**
三目運算符: ?:
成員訪問符: . .*
字長訪問符: sizeof
作用域符: ::
++運算符的重載:
前置++: Test operator++();
後置++: Test operator++(int);
此處的int僅作爲標記使用;
流運算符重載:
friend ostream& operator<<(ostream &out, const Test &t);
{
out << t.data;
return out;
}
作爲友元函數進行重載;
C++如何實現的重載:
編譯器在彙編階段根據函數的參數通過自己的一套命名方式
將函數進行一系列重命名,翻譯成另一個具有唯一性的名字(帶上函數的參數)
當加入extern "C" 修飾函數的時候用C的模式彙編
空間分配(new && delete):
new 等同於 C 語言中的 (強制轉化 *)malloc(sizeof(類型));
int *p = new int(10); //新建一個值爲10的整形
int *p = new int[10]; //新建一個有10個成員的整形數組
int *p = new Test; //調用構造函數申請空間(如果要求有參數必須寫參數)
int *p = new Test[10]; //構造10個對象!
//Tips: 如果要直接構造,一定要有默認(帶參)的構造函數
delete []p; //*** 通過delete刪除掉連續申請的對象空間 否則內存泄露
//方括號只起到標記作用,標識是釋放一個數組空間
new的步驟:
1.申請空間;
2.調用構造函數在申請的空間內構造對象;
delete的步驟:
1.調用析構函數析構對象;
2.釋放空間;
模板:
#include <typeinfo>
template<typename Type>
Max(Type a, Type b)
{
cout<<typeid(Type).name()<<endl;
//打印出Type的類型
return a>b ? a:b;
}
實現是先通過一系列操作與函數模板, 製作出相應類型的模板函數
最後再用模板函數來實現函數功能
類的形式類似;
可以直接調用:
Max(1,2);
Max(‘A’, ‘X’);
或者顯式調用:
Max(1,2);
Max(‘A’, ‘X’);
Gdb調試:
1.g++ -o -g
2.gdb
3.list
4.b 加斷點
5.run
new && delete:
1.new operator -> 1)分配空間 2)構造函數
(直接使用 new 關鍵字)
2.operator new -> 只分配空間
(直接使用 operator new 關鍵字)
可以重載new操作符來影響其分配空間的操作
void *operator new(size_t sz)
{
void *p = malloc(sz);
return p;
}
要求返回值void * 傳入參數 size_t
同時如果你重載了new操作符,就要求你重載delete操作符
void operator delete(void *p)
{
free(p);
}
*Tips:free 與 malloc對應
new 與 delete對應
operator new 與 operator delete 對應
同理 new[] 與 delete[] 也可以重載
實際上new[] 在申請空間的時候,
頭部會多出一部分cookie空間, 大小爲一個指針的大小
存儲着用戶的信息:起始位置,釋放多少個對象
此時纔可以以delete[]來釋放相應的空間
類裏面也可以重載new delete操作符,而且會被對象優先使用
如果是void*p = new Test(10);
那麼delete p的時候 不會調用類的析構函數;
3.placement new
通過malloc開闢空間之後
int p = (int )malloc(sizeof(int) * 10)
可以通過new(p)int(10)來對申請的空間進行賦值
這種語法稱之爲定位new
這樣的new也是可以重載的:
void *operator new(size_t sz, void *data, int pos)
{
return (data + pos);
}
則使用方法變爲
new(p, 3)int(200);
對p所指的第三個位置進行賦值200的操作
繼承和多態:
子類雖然公有繼承了基類的私有成員
但是依然不能在自己的方法中改變基類
正確的用法是在基類中設置相應的設置方法來設置基類的成員
父類的信息能否被子類調動?
***父類任意私有數據都不能被子類直接調用
但是父類的公有方法與保護方法都可以被子類的方法調用
只有公有方法可以被對象直接訪問
保護方法存在的意義:
***保護只在繼承的時候體現它的性質
不想被外部的對象調用, 爲了給子類提供藉口而存在
其他一切特點等同於私有
class C: D
默認是私有繼承 (class C: private D)
多繼承:
多繼承的構造函數順序就是繼承列表從左往右
同時先構造成員的類對象再構造自身類對象
構造函數書寫方法:
C(a, b, c): A(a), B(b), C(c){}
子類要調用基類的構造方法
二義性:
父類有同名的變量
那麼需要通過加入 父類:: 來避免二義性
虛繼承:
可以避免繼承同一個基類產生變量的二義性
同名隱藏:
如果子類和父類有同名的方法
那麼父類的同名方法會完全被隱藏(哪怕是重載)
但是可以通過使用::這個來直接調用父類方法
看書:
1.重載 2.覆蓋 3.隱藏