1.對象移動
1.1右值引用
右值引用區別于普通引用,用兩個&表示
返回左值引用的函數,連同賦值、下標、解引用和前置遞增遞減運算符返回左值
返回非引用的函數,連同算術、關系、位以及后置遞增遞減運算符都生成右值
我們不能將左值引用綁定到一個右值上,但可以使用const左值引用或右值引用綁定到一個右值上
左值持久,右值短暫
我們不能將右值引用綁定到一個變量上
1.2 標準庫move函數
位于頭文件utility
int &&i1 = std::move(r2);
我們可以使用move函數將左值強制轉換為右值
這也意味著,我們使用move函數之后可以銷毀對象,也可以給對象賦予一個新值,但我們不能使用這個對象了
1.3移動構造函數和移動賦值運算符
移動構造函數的參數為:類名&&
這里引入一個新名詞 noexcept 不拋出任何異常,在參數列表后添加
我們在移動構造函數中必須另類中的數據成員回歸成可析構
移動賦值運算符函數類似,但前提是要檢查返回值和傳進來的右值地址是否相同
1.4移動迭代器
函數make_move_iterator函數接受一個迭代器,使其成為一個移動迭代器,將其與普通的迭代器使用即可
區別在于我們使用這個函數后,這個迭代器以后就無法使用了,另外使用時會觸發類的移動構造函數
2.重載與調用函數對象
2.1 重載后置++--
vec operator++(int)
{vec ret = *this;++*this;return ret;
}
2.2函數調用重載
class add
{
public:int operator() (int i,int j){return i +j;}
};
add Add;
int i = Add(2,4);
2.3 lambda是函數對象
//假設有這么一個算法表達式
stable_sort(words.begin(),words.end(),[](const string&a,const string &b) { return a.size()<b.size(); });
//其行為等價于
class ShorterString
{
public:bool operator()(const string&a,const string&b) const {return a.size()<b.size();}
};
stable_sort(words.begin(),words.end(),ShorterString());
2.4標準庫定義的函數對象
頭文件:functional
plus<int>add;
int i = add(2,4);
sort(vec.begin(),vec.end(),greater<int>());//按降序排序
2.5可調用對象于function
int (int,int);//是一個函數類型,接受兩個int,返回一個int
int mod (int i,int j);//普通函數
auto add = [](int i,int j) {return i + j;};//lambda
struct divide{int operator() (int i,int j);//函數對象類
};
我們可以通過標準庫function來統一這三種類型
比如我們需要做一個桌面計算器
map<string,function<int(int,int)>>cal;//定義一個map
cal["+"] = add;
cal["%"] = mod;
cal["/"] = divide();
但我們必須注意二義性的問題
如有必要,必須這樣做
int (*p)(int,int)=add;
cal["+"] = p;
3.重載,類型轉換與運算符
3.1類型轉換運算符
基本形式:
operator type() const ;
4.類繼承
4.1虛函數
虛函數通常在基類前聲明virtual
為了防止派生類的虛函數并未覆蓋基類中的虛函數,我們必須在派生類虛方法的參數列表后加上 override
如果將一個函數設為final,那么它的派生類不可覆蓋他
4.2回避虛函數的機制
必須顯式說明,Base::fun();
4.3抽象基類
若一個基類有一個函數在參數列表后加上了 =0
那么該基類成為抽象基類
抽象基類不能顯式聲明
4.4派生類與基類的轉換
假設D繼承B,有三種情況
只有公有繼承能讓用戶能直接使用派生類轉換為基類
任何繼承方式,D的成員函數和友元都可以使用派生類轉換為基類
只有公有與保護繼承,D的成員和友元可以使用轉換