模板 c++另一種編程思想稱為泛型編程,主要利用的技術就是模板 c++提供兩種模板機制:函數模板和類模板 函數模板 建立一個通用函數,函數的返回值類型和形參類型可以不具體指定,用一個虛擬的類型來代表 語法: template<typename T> //或者 template<class T> 函數 ...
模板
c++另一種編程思想稱為泛型編程,主要利用的技術就是模板
c++提供兩種模板機制:函數模板和類模板
函數模板
建立一個通用函數,函數的返回值類型和形參類型可以不具體指定,用一個虛擬的類型來代表
語法:
template<typename T>
//或者
template<class T>
函數聲明或定義
當使用class的時候,如果T有子類,編譯器會認為是聲明,所以還是使用typename吧
template<typename T>
void test(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
int main() {
int a = 1, b = 2;
//自動推導類型
test(a, b);
//指定類型
test<int>(a, b);
cout << a << "==" << b << endl;
}
註意事項:
自動類型推導,必須推導出一致的數據類型T才可以使用
模板必須要確定出T的數據類型,才可以使用
template<typename T>
void test(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
int main() {
int a = 1, b = 2;
char c='1';
//自動推導類型錯誤,因為兩個類型不同
test(a, c);
}
template<typename T>
void test() {
cout << "hhhh" << endl;
}
int main() {
test();//錯誤,因為推導不出T是什麼類型
}
template<typename T>
void test() {
cout << "hhhh" << endl;
}
int main() {
test<int>(); //明確指定就可以
test<string>();//這個也可以
}
普通模板和函數模板區別
- 普通函數調用時可以發生自動類型轉換(隱式類型轉換)
- 函數模板調用時,如果利用自動類型推導,不會發生隱式類型轉換
- 函數模板如果利用顯示指定的方法,可以發生類型轉換
普通函數會發生隱式轉換,例如下麵的例子中,將char類型的c轉換為了int,對應的就是c的ascll碼
void print1(int a, int b) {
cout << a + b << endl;
}
int main() {
int a = 1;
char b = 'c';
print1(a,b);
}
而使用模板函數時
template<typename T>
void print(T a,T b) {
cout << a+b << endl;
}
int main() {
int a = 1;
char b = 'c';
print(a,b); //報錯
}
template<typename T>
void print(T a,T b) {
cout << a+b << endl;
}
int main() {
int a = 1;
char b = 'c';
print<int>(a,b); //除非我們指定了數據類型為int
}
普通函數和模板函數的調用規則
- 如果函數模板和普通函數都可以實現,優先調普通函數
- 可以通過空模板參數來強制調用函數模板
- 函數模板也可以發生重載
- 如果函數模板可以產生更好的匹配,優先調用函數模板
如果函數模板和普通函數都可以實現,優先調普通函數
template<typename T>
void test(T a) {
cout <<"函數模板" << endl;
}
void test(int a) {
cout << "普通函數" << endl;
}
int main() {
int a = 1;
test(a);
}
結果:普通函數
template<typename T>
void test(T a) {
cout <<"函數模板" << endl;
}
void test(int a);
int main() {
int a = 1;
test(a);
}
如果普通函數只有聲明也是調用普通函數,會報錯沒有找到定義
可以通過空模板參數來強制調用函數模板
template<typename T>
void test(T a) {
cout <<"函數模板" << endl;
}
void test(int a) {
cout << "普通函數" << endl;
}
int main() {
int a = 1;
test<>(a);
}
這樣就可以強制調用函數模板,當然,尖括弧裡面隨便寫個類型也可以,但沒必要
函數模板也可以發生重載
template<typename T>
void test(T a) {
cout <<"函數模板一個參數" << endl;
}
template<typename T>
void test(T a,T b) {
cout << "函數模板兩個參數" << endl;
}
int main() {
int a = 1;
test<>(a); //函數模板一個參數
test<>(a,a); //函數模板兩個參數
}
如果函數模板可以產生更好的匹配,優先調用函數模板
template<typename T>
void test(T a) {
cout <<"函數模板一個參數" << endl;
}
void test(int a) {
cout << "普通函數" << endl;
}
int main() {
char a = '1';
test(a);
}
會優先使用函數模板,因為普通函數確定了類型為int,而char需要轉int,調用函數模板則不需要任何轉換
模板的局限性
模板並不是萬能的,例如
template<typename T>
bool test(T& a,T& b) {
return a == b;
}
int main() {
char a = '1';
char b = '2';
cout<<test(a,b);
}
當我們傳基礎的數據類代碼可以正常使用,但是當傳入的數據是自定義類型的時候
class A {
public:
string name;
};
template<typename T>
bool test(T& a,T& b) {
return a == b;
}
int main() {
A a1 = { "小明" };
A a2 = { "大明" };
cout<<test(a1,a2);
}
就會報錯了,因為沒有找到A類型的==判斷
解決辦法有兩個:
1 重寫運算符
class A {
public:
string name;
bool operator==(A& a) {
return (this->name == a.name);
}
};
template<typename T>
bool test(T& a, T& b) {
return a == b;
}
int main() {
A a1 = { "小明" };
A a2 = { "大明" };
cout << test(a1, a2);
}
2 重寫一個針對A類的函數模板
class A {
public:
string name;
};
template<typename T>
bool test(T& a, T& b) {
return a == b;
}
template<> bool test(A& a, A& b) {
return a.name == b.name;
}
int main() {
A a1 = { "小明" };
A a2 = { "大明" };
cout << test(a1, a2);
}
利用具體化的模板,可以解決自定義類型的通用化
類模板
建立一個通用的類,類中的成員數據類型可以不具體指定,用一個虛擬的類型來代表
語法:
template<typename T>
class 類名 {
};
//聲明下麵的類中可以使用這兩個類型
template<typename NameType,typename AgeType>
class A {
public:
NameType name;
AgeType age;
};
int main() {
//使用時指定兩個類型
A<string, int> a = { "小明",19 };
cout << a.age << "==" << a.name << endl;
}
類模板和函數模板區別
-
類模板沒有自動推導類型的使用方式
template<typename NameType,typename AgeType> class A { public: A(NameType _name, AgeType _age) { this->name = _name; this->age = _age; } NameType name; AgeType age; }; int main() { //A a("哈哈哈", 1); 報錯,類模板沒有自動推導 A<string,int> a("哈哈哈", 1); //可以正常使用 cout << a.age << "==" << a.name << endl; }
-
類模板在模板參數列表中可以有預設參數
template<typename NameType, typename AgeType=int> //這裡給AgeType設置了預設類型為int class A { public: A(NameType _name, AgeType _age) { this->name = _name; this->age = _age; } NameType name; AgeType age; }; int main() { //下麵在使用時就只需要指定一個string即可 A<string> a("哈哈哈", 1); cout << a.age << "==" << a.name << endl; }
需要註意的是,如果有兩個或多個參數,只能從最右邊開始指定預設類型
例如下麵的就是錯誤的
template<typename NameType=string, typename AgeType>
類模板中的成員函數創建時機
類模板的成員函數和普通類的成員函數創建時機是有區別的
- 普通類中的成員函數一開始就可以創建
- 模板類中的成員函數在調用的時候才會創建
class A {
public:
void func1() {
cout << "A-func" << endl;
}
A() {
cout << "A-init"<<endl;
}
};
class B {
public:
void func2() {
cout << "A-func" << endl;
}
};
template <typename T>
class MyRun {
public:
T t;
void run1() {
t.func1();
}
void run2() {
t.func2();
}
};
int main() {
MyRun<A> m;
m.run1();
//m.run2();
}
當main方法中什麼都不寫的時候,可以正常運行,因為MyRun
類中的屬性t並沒有確認是什麼類型,只有在運行的時候才能確認t的類型,判斷t有沒有func1或func2的函數
當指定類型為A的時候就已經初始化創建了一個A對象
A-init
A-func
類模板對象做函數參數
三種傳入方式
- 指定傳入類型
- 參數模板化
- 整個類模板化
1 指定傳入類型
template <typename NameType,typename AgeType>
class User {
public:
NameType name;
AgeType age;
User(NameType _name,AgeType _age) :name(_name), age(_age) {
}
};
//直接標明都是什麼類型
void print(User<string, int>& u) {
cout << u.name << "==" << u.age << endl;
}
int main() {
User<string, int> user("小明", 20);
print(user);
}
2 參數模板化
template <typename NameType,typename AgeType>
class User {
public:
NameType name;
AgeType age;
User(NameType _name,AgeType _age) :name(_name), age(_age) {
}
};
//模板的名稱不需要和類模板定義名稱一樣,只是單純定義函數模板
template <typename F_NameType,typename F_AgeType>
void print(User<F_NameType, F_AgeType>& u) {
cout << u.name << "==" << u.age << endl;
cout <<"F_NameType的數據類型為:" << typeid(F_NameType).name() << endl;
cout <<"F_AgeType的數據類型為:" << typeid(F_AgeType).name() << endl;
}
int main() {
User<string, int> user("小明", 20);
print(user);
}
3 整個類模板化
template <typename NameType,typename AgeType>
class User {
public:
NameType name;
AgeType age;
User(NameType _name,AgeType _age) :name(_name), age(_age) {
}
};
//再定義有一個模板函數作為接收參數
template <typename T>
void print(T& u) {
cout << u.name << "==" << u.age << endl;
cout <<"T的數據類型dfsdfs為:" << typeid(T).name() << endl;
}
int main() {
User<string, int> user("小明", 20);
print(user);
}
類模板與繼承
- 當子類繼承的父類是一個類模板時,子類在聲明的時候,要指出父類中T的類型
- 如果不指定,編譯器無法給子類分配記憶體
- 如果想靈活指定父類中的T類型,子類也需要變為類模板
1 當子類繼承的父類是一個類模板時,子類在聲明的時候,要指出父類中T的類型
template <typename T>
class Father {
public:
T obj;
};
class Son : public Father<int> {
};
int main() {
Son s;
s.obj = 100;
cout << s.obj << endl;
}
2 如果想靈活指定父類中的T類型,子類也需要變為類模板
template <typename T>
class Father {
public:
T obj;
};
//聲明同時指定T2類型
template <typename T1,typename T2=int>
class Son : public Father<T1> {
public:
T2 t2;
};
int main() {
//傳入的是Father的模板類型,Son的已經有預設類型了
Son<int> s;
s.obj = 100;
s.t2 = 200;
cout << s.obj << endl;
cout << s.t2 << endl;
}
類模板成員函數類外實現
template<typename T>
class A {
public:
A(T n); //聲明構造
void print(); //聲明函數
T number;
};
//類外實現構造
template<typename T>
A<T>::A(T n) {
this->number = n;
}
//類外實現函數
template<typename T>
void A<T>::print() {
cout << this->number;
}
int main() {
A<int> a(1);
a.print();
}
類模板分文件編寫
問題: 類模板中成員函數創建時機在調用階段,導致分文件編寫時鏈接不到
解決方式1: 直接包含.cpp源文件
解決方式2 將聲明和實現寫到同一個文件中,並將尾碼改為hpp,hpp是約定名稱,不是強制
A.h
#pragma once
#include <iostream>
#include<string>
using namespace std;
template<typename T>
class A {
public:
A(T n);
void print();
T number;
};
A.cpp
#include "A.h"
template<typename T>
A<T>::A(T n) {
this->number = n;
}
template<typename T>
void A<T>::print() {
cout << this->number;
}
主文件
#include "A.h"
int main() {
A<int> a(1);
a.print();
}
運行報錯,無法解析符號
方式1:把主文件中的#include "A.h"
改為#include "A.cpp"
方式2:將A.cpp的內容移動到A.h中,然後修改A.h為A.hpp
A.hpp
#pragma once
#include <iostream>
#include<string>
using namespace std;
template<typename T>
class A {
public:
A(T n);
void print();
T number;
};
template<typename T>
A<T>::A(T n) {
this->number = n;
}
template<typename T>
void A<T>::print() {
cout << this->number;
}
主函數
#include "A.hpp"
int main() {
A<int> a(1);
a.print();
}
類模板和友元
全局函數類外實現- 直接在類中聲明友元即可
全局函數類外實現,需要提前讓編譯器知道全局函數的存在
類內實現:
#include <iostream>
#include<string>
using namespace std;
template <typename T>
class G {
//這個就是全局函數,不是成員函數
//還有一種是類內聲明,類外實現,這個是直接實現
//因為要指定那個方法作為當前類的友元,所以會在類中定義全局函數
friend void print(G<T> g) {
cout << g.name << endl;
}
public:
G(T t) {
this->name = t;
}
private:
T name;
};
int main() {
G<string> g("小明");
print(g);
}
類外實現1:
template <typename T>
class G {
//標明這個函數是一個函數模板
template <typename T>
friend void print(G<T>& g);
public:
G(T t) {
this->name = t;
}
private:
T name;
};
//實現
template <typename T>
void print(G<T>& g) {
cout << g.name << endl;
};
int main() {
G<string> g("小明");
print(g);
}
類外實現2:
//因為print方法提前到了G類的定義前
//需要讓編譯器提前知道還有個G類
template <typename T>
class G;
//在G類上方定義函數模板,讓編譯器知道這個方法
template <typename T>
void print(G<T>& g) {
cout << g.name << endl;
};
template <typename T>
class G {
//=======註意! 需要加一個空模板參數列表
friend void print<>(G<T>& g);
public:
G(T t) {
this->name = t;
}
private:
T name;
};
int main() {
G<string> g("小明");
print(g);
}
練習-使用模板類實現一個容器
MyArray.hpp
#pragma once
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class MyArray {
public:
MyArray(int _size) {
//cout << "有參構造" << endl;
this->size = _size;
this->count = 0;
this->p = new T[_size];
}
//重寫拷貝構造,解決淺拷貝問題
MyArray(const MyArray& arr) {
//cout << "拷貝構造" << endl;
this->count = arr.count;
this->size = arr.size;
//深拷貝
this->p = new T[arr.size];
for (int i = 0; i < size; i++) {
this->p[i] = arr.p[i];
}
}
//重載賦值符號,解決淺拷貝問題
MyArray& operator=(const MyArray& arr) {
//cout << "賦值重載" << endl;
if (this->p != NULL) {
delete[] this->p;
p = NULL;
}
this->count = arr.count;
this->size = arr.size;
this->p = new T[arr.size];
for (int i = 0; i < size; i++) {
this->p[i] = arr.p[i];
}
return *this;
}
T& operator[](int index) {
return this->p[index];
}
int getSize() {
return this->size;
}
int getCount() {
return this->count;
}
~MyArray() {
//cout << "析構函數" << endl;
if (this->p != NULL)
{
//刪除數組
delete[] this->p;
p = NULL;
}
}
void add(const T& t) {
if (this->count == this->size) {
cout << "已經滿了" << endl;
return;
}
this->p[count++] = t;
}
void remove() {
if (this->count == 0) {
return;
}
this->p[--count] = 0;
}
private:
T* p;
//數組已占用個數
int count;
//數組大小
int size;
};
主函數
1 測試基礎數據類型
#include <iostream>
#include "MyArray.hpp" //引入自定義的頭文件需要使用""而不是<>
#include<string>
using namespace std;
int main() {
MyArray<int>* p = new MyArray<int>(10);
cout << "數組大小:" << p->getSize() << endl;
cout << "數組容量:" << p->getCount() << endl;
for (int b = 0; b < 10; b++) {
p->add(b);
}
cout << "數組容量:" << p->getCount() << endl;
for (int i = 0; i < p->getCount(); i++) {
//因為是指針,所有需要先解引用然後再[下標]取值
cout << (*p)[i] << endl;
}
p->remove();
p->remove();
p->remove();
MyArray<int> arr2 = *p;
cout << "arr2===copy===:" << endl;
for (int i = 0; i < arr2.getCount(); i++) {
cout << arr2[i] << endl;
}
cout << "arr2===end:" << endl;
for (int i = 0; i < p->getCount(); i++) {
cout << (*p)[i] << endl;
}
delete p;
p = NULL;
}
2 測試自定義數據類型
#include <iostream>
#include "MyArray.hpp"
#include<string>
using namespace std;
class A {
public:
//無參構造,用於自定義容器中的深拷貝的創建對象
// this->p = new T[_size];
A() {}
A(string _name, int _age) :name(_name), age(_age) {
}
string name;
int age;
};
ostream& operator<<(ostream& o, A& a) {
cout <<"年齡:" << a.age<<" 姓名:" << a.name;
return o;
}
int main() {
MyArray<A> arr(10);
A a2 = { "A2",20 };
A a3 = { "A3",30 };
A a4 = { "A4",40 };
arr.add(a1);
arr.add(a2);
arr.add(a3);
arr.add(a4);
for (int i = 0; i < arr.getCount(); i++) {
cout << arr[i]<<"====地址:"<<&(arr[i]) << endl;
}
MyArray<A> arr2(arr);
for (int i = 0; i < arr2.getCount(); i++) {
cout << arr2[i] <<"====地址:" << &(arr[i])<< endl;
}
cout << "兩個數組地址==arr:" << (int) & arr << " arr2:" << (int)&arr2 << endl;
}
STL容器
-
STL(Standard Template Library) 標準模板庫
-
STL從廣義上分為容器,演算法,迭代器
-
容器和演算法直接通過迭代器進行無縫銜接
-
STL幾乎所有代碼都使用了模板類或模板函數
STL六大組件
容器,演算法,迭代器,仿函數,適配器(配接器),空間配置器
- 容器:各種數據結構,如vector,list,deque,set,map等,用來存放數據
- 演算法:各種常用的演算法,如sort,find,copy,for_each等
- 迭代器:扮演了容器與演算法之間的膠合器
- 仿函數:行為類似函數,可作為演算法的某種策略
- 適配器:一種用來修飾容器或仿函數或迭代器介面的東西
- 空間配置器:賦值空間的配置與管理
容器
常用數據結構:數組,鏈表,數,棧,隊列,集合等
容器分為序列式容器和關聯式容器
- 序列式容器:強調值的排序,序列式容器中每個元素都有固定的位置
- 關聯式容器:二叉樹結構,各元素之間沒有嚴格的物理上的順序關係
演算法
演算法分為質變演算法和非質變演算法
質變演算法:指運算過程中會改變區間內容的元素內容例如拷貝,替換,刪除等
非質變演算法:指運算過程中不會更改區間的元素內容,例如查找,計數,變數,尋找極值等
迭代器
提供一種方法,能夠依序尋訪某個容器中所包含的每個元素,而又無需暴露該容器的內部表示方式
每個容器都有自己的迭代器,迭代器非常類似於指針,初學階段可以先理解為指針
迭代器種類:
輸入迭代器:對數據的只讀訪問,支持++ == !=
輸出迭代器:對數據的只寫操作,支持++
前向迭代器 讀寫操作,並能向前推進迭代器 支持++ == !=
雙向迭代器 讀寫,並能向前和向後操作 支持++ --
隨機訪問迭代器 讀寫操作 可以跳躍的訪問任何數據 支持++ -- [n] -n < <= > >=
string容器
**string和char ***區別
- char *是一個指針
- string是一個類,內部封裝了char* 管理這個字元串,是一個char*型的容器
string 構造函數
string()
創建一個空字元串,例如string s;string(const char* s)
使用字元串s初始化string(const string& str)
使用一個string對象來初始化另一個string(int n,char c)
使用n個字元c初始化
int main() {
//預設構造
string s;
const char* str = "hello!";
string s1(str);
cout << "s1" << s1 << endl;
//拷貝構造
string s2(s1);
cout << "s2" << s2 << endl;
//4個h
string s3(4, 'h');
cout << "s3" << s3 << endl;
}
string 賦值操作
string& operator=(const char* s)
char*類型字元串賦值給當前字元串string& operator=(const string& s)
字元串s賦值給當前字元串string& operator=(char c)
字元賦值給當前字元串string& assign(const char* s)
字元串s賦值給當前字元串string& assign(const char* s,int n)
把字元串s的前n個字元賦值給當前字元串string& assign(const string& s)
把字元串s賦值給當前字元串string& assign(int n,char c)
用n個字元c賦值給當前字元串
int main() {
//預設構造
string s;
const char* str = "hello!";
s = str;
cout << "s=" << s << endl;
string s1 = s;
cout << "s1=" << s1 << endl;
string s2;
s2 = 'a';
cout << "s2=" << s2 << endl;
string s3;
s3.assign("hellowwww");
cout << "s3=" << s3 << endl;
string s4;
s4.assign("hellowwww",3);
cout << "s4=" << s4 << endl;
string s5;
s5.assign(s4);
cout << "s5=" << s5 << endl;
string s6;
s6.assign(6, 't');
cout << "s6=" << s6 << endl;
}
string 拼接
string& operator+=(const char* str)
string& operator+=(const char c)
string& operator+=(const string& str)
string& append(const char* s)
把s字元串拼接到當前字元串結尾string& append(const char* s,int n)
把c字元串前n個字元拼接到當前字元串結尾string& append(const string& s)
同operator+=(const string& str)string& append(const string& s,int pos,int n)
字元串s中從pos開始的n個字元拼接到字元串結尾
int main() {
//預設構造
string s = "hello!";
s += " i ";
s += 'a';
string s1 = "m";
s += s1;
s.append(" j");
s.append("a==", 1);
s.append(s1);
string s2 = "asme";
s.append(s2,3,1);
cout << s << endl;
// hello! i am jame
}
string 查找替換
int find(const string& str,int pos=0) const
查找str第一次出現的位置,從pos開始int find(const char* s,int pos=0) const
查找s第一次出現的位置,從pos開始查找int find(const char* s,int pos,int n) const
從pos位置查找s前n個字元第一次出現的位置int find(const char c,int pos=0) const
查找字元c第一次出現的位置int rfind(const string& str,int pos=npos) const
查找str最後一次出現的位置,從pos開始查找int rfind(const char* s,int pos=npos) const
查找s最後一次出現的位置,從pos開始查找int rfind(const char* s,int pos,int n) const
從pos查找s前n個字元最後一次出現的位置int rfind(const char c,int pos=0) const
查找字元c最後一次出現的位置string& replace(int pos,int n,const string& str)
從pos開始n個字元替換為strstring& replace(int pos,int n const char* s)
替換從pos開始n個字元為s
find和rfind區別 find是從左往右,rfind是從右往左
int main() {
string s = "2===2=";
string s1 = "6";
cout<<s.find(s1)<<endl; //s.find(s1,0) 省略
cout << s.find("2") << endl; //s.find("2",0) 省略
cout << s.find("234", 0, 1) << endl; //先把234拆開,從0開始,拆一個,獲取到2,然後再查
cout << s.find('2') << endl;//s.find('2',0)省略
cout << s.rfind(s1,6) << endl;//從下標6開始從右往左查
cout << s.rfind("2",6) << endl;//從下標6開始從右往左查
cout << s.rfind('2',6) << endl;//從下標6開始從右往左查
cout<<s.replace(0, 1, s1)<<endl;//從0開始1個字元替換為6
cout<<s.replace(0, 1, "7")<<endl;//從0開始1個字元替換為6
}
string 比較
字元串比較是按字元的ASCII碼進行對比
= 返回0 > 返回 1 < 返回-1
int compare(const string& s) const
與字元串s比較int compare(const char* s)const
與字元串s比較
int main() {
string s = "hello";
string s1 = "hello";
string s2 = "xello";
cout << (s.compare(s1) == 0) << endl;
cout << (s.compare(s2) == 0) << endl;
cout << (s.compare("hello") == 0) << endl;
cout << (s.compare("xello") == 0) << endl;
}
string 字元串存取
char& operator[](int n)
通過[]獲取字元char& at(int n)
通過at方法獲取字元
int main() {
string s = "hello";
s[0] = 'y';
for (int i = 0; i < s.length(); i++) {
cout << s[i];
}
s.at(0) = 'y';
for (int i = 0; i < s.length(); i++) {
cout << s.at(i);
}
}
string 插入和刪除
string& insert(int pos,const char* s);
插入字元串string& insert(int post,const string& str)
插入字元串string& insert(int pos,int n,char c)
pos位置插入n個字元cstring& erase(int pos,int n=pos)
刪除從pos開始的n個字元
int main() {
string s = "hello";
string s1 = "wu";
cout<<s.insert(1, "+")<<endl; //在下標1後面插入---
cout << s.insert(1, s1) << endl; //在下標1後面插入s1
cout << s.insert(1, 4, 'x') << endl; //在下標1後面插入4個字元x
cout << s.erase(1, 2) << endl;//從下標1後刪除2個字元
}
string 子串
string substr(int pos=0,int n=pos) const
返回從pos開始的n個字元組成的字元串
int main() {
string s = "hello";
cout << s.substr() << endl;
cout << s.substr(0,1) << endl;
}
vector容器
vector數據結構和數組非常相似,也稱之為單端數組,但是不同於數組是靜態空間,vector是可以動態擴展的
動態擴展
並不是在原空間後繼續開闢空間,而是找一段更大的空間,之後將原數據複製到新空間上,釋放原空間
vector的迭代器是支持隨機訪問的
容器:vector
演算法:for_each
迭代器:vector<int>::iterator
#include <iostream>
#include <vector>
using namespace std; //vector需要導入
#include<algorithm> //for_each 導入
void print(int val) {
cout << val;
}
int main() {
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
//直接通過下標訪問
int& a = v[1];
//通過迭代器訪問1
//vector<int>::iterator itBegin = v.begin();
//vector<int>::iterator itEnd = v.end();
//while (itBegin != itEnd) {
// cout << *itBegin << endl;
// itBegin++;
//
//}
//
//通過迭代器訪問2
//for (vector<int>::iterator itBegin = v.begin(); itBegin != v.end(); itBegin++){
// cout << *itBegin << endl;
//
//}
//通過for_each
for_each(v.begin(), v.end(), print);
}
添加自定義的類型
class A {
public :
string name;
};
int main() {
vector<A> v;
A a1 = { "a1" };
A a2 = { "a2" };
A a3 = { "a3" };
v.push_back(a1);
v.push_back(a2);
v.push_back(a3);
//通過迭代器訪問2
for (vector<A>::iterator itBegin = v.begin(); itBegin != v.end(); itBegin++){
cout << (* itBegin).name << endl;
}
}
存放類的指針
int main() {
vector<A*> v;
A a1 = { "a1" };
A a2 = { "a2" };
A a3 = { "a3" };
v.push_back(&a1);
v.push_back(&a2);
v.push_back(&a3);
//通過迭代器訪問2
for (vector<A*>::iterator itBegin = v.begin(); itBegin != v.end(); itBegin++){
cout << (*itBegin)->name << endl;
cout << (**itBegin).name << endl;//或者
}
}
容器記憶體放容器
vector<vector<A>> v;
A a1 = { "a1" };
A a2 = { "a2" };
A a3 = { "a3" };
vector<A> v1;
v1.push_back(a1);
v1.push_back(a2);
v1.push_back(a3);
vector<A> v2;
v2.push_back(a1);
v2.push_back(a3);
v2.push_back(a2);
vector<A> v3;
v3.push_back(a1);
v3.push_back(a3);
v3.push_back(a2);
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
for (vector<vector<A>>::iterator itBegin = v.begin(); itBegin != v.end(); itBegin++){
for (vector<A>::iterator itb = itBegin->begin(); itb != itBegin->end(); itb++) {
cout << itb->name << endl;
}
}
vector 構造
vector<T> v
採用模板實現,預設構造vector(v.begin(),v.end())
將v[begin(),end()]區間中的元素拷貝給本身vector(n,elem)
構造將n個elem拷貝給本身vector(const vector &vec)
拷貝構造
int main() {
vector<int> v;
for (int i = 0; i < 10; i++){
v.push_back(i);
}
//把v的begin到end的數據複製給v2
vector<int> v2(v.begin(), v.end());
//創建10個100放到v3
vector<int> v3(10, 100);
//拷貝構造
vector<int> v4(v3);
for (vector<int>::iterator it = v3.begin(); it != v3.end(); it++) {
cout << *it << endl;
}
}
vector 賦值操作
vector& operator=(const vector &vec)
重載=assign(beg,end)
將v[begin(),end()]區間中的元素拷貝給本身assign(n,elem)
將n個elem拷貝賦值給本身
int main() {
vector<int> v;
for (int i = 0; i < 10; i++){
v.push_back(i);
}
//直接=賦值
vector<int> v2 = v;
vector<int> v3;
//把v的begin到end數據賦值給v3
v3.assign(v.begin(), v.end());
//放10個100到v4裡面
vector<int> v4;
v4.assign(10, 100);
for (vector<int>::iterator it = v4.begin(); it != v4.end(); it++) {
cout << *it << endl;
}
}
vector 容量和大小
empty()
返回容器是否為空capacity()
容器的容量size()
返回容器中的元素個數resize(int num)
重新定義容器長度為num,若大於原長度,則新位置填充預設值,若小於原長度,超出部分元素被刪除resize(int num,elem)
重新定義容器長度為num,若大於原長度,則新位置填充elem,若小於原長度,超出部分元素被刪除
int main() {
vector<int> v;
for (int i = 0; i < 10; i++){
v.push_back(i);
}
cout << v.empty() << endl;
cout << v.capacity() << endl;
cout << v.size() << endl;
v.resize(9);
v.resize(9,4);
}
vector 插入和刪除
push_back(ele)
尾部插入元素elepop_back()
刪除最後一個元素insert(const_iterator pos,ele)
迭代器指向位置pos插入元素eleinsert(const_iterator pos,int count,ele)
迭代器指向位置pos插入count個元素eleerase(const_iterator pos)
刪除迭代器指向的元素erase(const_iterator start,const_iterator end)
刪除迭代器從start到en之間的元素clear()
刪除容器中所有元素
int main() {
vector<int> v;
for (int i = 0; i < 10; i++){
v.push_back(i);
}
v.push_back(1);
v.pop_back();
v.insert(v.begin(), 1);
v.insert(v.begin(), 1, 2);
v.erase(v.begin());
v.erase(v.begin(), v.end());
v.clear();
}
vector 數據存取
at(int index)
返回索引指向的數據operator[]
返回索引指向的數據front()
返回容器中第一個元素back()
返回最後一個元素
int main() {
vector<int> v;
for (int i = 0; i < 10; i++) {
v.push_back(i);
}
cout << v.at(2) << endl;
cout << v[2] << endl;
cout << v.front() << endl;
cout << v.back() << endl;
}
vector 互換容器
swap(vec)
與另一個vector容器互換元素
int main() {
vector<int> v;
for (int i = 0; i < 10; i++) {
v.push_back(i);
}
vector<int> v2;
for (int i = 0; i < 5; i++) {
v2.push_back(i);
}
v.swap(v2);
for (vector<int>::iterator t = v.begin(); t != v.end(); t++) {
cout << *t;
}
cout << "\n";
for (vector<int>::iterator t = v2.begin(); t != v2.end(); t++) {
cout << *t ;
}
}
還可以使用swap來重構vector的大小
例如有一個容量為1萬的容器,之後刪除到只剩10個元素,現在希望縮小它的容量
int main() {
vector<int> v;
for (int i = 0; i < 10000; i++) {
v.push_back(i);
}
vector<int>(v).swap(v);
}
首先vector<int>(v)
調用複製拷貝來初始化一個新的vector對象,會使用v的元素個數來初始化新vector的容量大小,之後交換兩個容器的指針,因為是匿名對象,運行完銷毀原來的容器占用空間
vector 預留空間
減少vector在動態擴展容量時的次數
reserve(int len)
給容器預留len個位置,預留位置不可訪問,不初始化
int main() {
vector<int> v;
// v.reserve(100000);
int number = 0;
int* p = NULL;
for (int i = 0; i < 100000; i++) {
v.push_back(i);
if (p != &(v[0])) {
p = &(v[0]);
number++;
}
}
//查看擴容次數
cout << number << endl;
}
deque容器
雙端操作,可以對頭端進行插入刪除,也支持隨機訪問
deque與vector的區別
-
vector對於頭部的插入刪除效率低,數據量越大,效率越低
-
deque相對vector頭部的插入刪除速度要快
-
vector訪問元素時的速度會比deque快
-
deque<T>
deqT; 預設構造 -
deque(beg,end)
構造函數將beg,end區間的元素拷貝給本身 -
deque(n,elem)
構造函數將n個elem拷貝給本身 -
deque(const deque &deq)
拷貝構造
#include <iostream>
#include <deque>
using namespace std;
void pirnt(deque<int> &d) {
for (deque<int>::iterator i = d.begin(); i != d.end(); i++) {
cout << *i << endl;
}
}
int main() {
//預設構造
deque<int> d;
for (int i = 0; i < 10; i++)
{
//尾部添加
//d.push_back(i);
//頭添加
d.push_front(i);
}
//pirnt(d);
cout << "====" << endl;
deque<int> d2(++d.begin(), d.end());
//初始化10個100
deque<int> d3(10, 100) ;
//拷貝構造
deque<int> d4(d3);
pirnt(d4);
}
deque賦值操作
deque&~operator=(const deque &deq)
重載等號assign(beg,end)
將beg,end區間數據拷貝賦值給本身assign(n,elem)
將n個elem賦值給本身
#include <deque>
using namespace std;
void pirnt(const deque<int> &d) {
for (deque<int>::const_iterator i = d.begin(); i != d.end(); i++) {
cout << *i << endl;
}
}
int main() {
//預設構造
deque<int> d;
for (int i = 0; i < 10; i++)
{
//尾部添加
//d.push_back(i);
//頭添加
d.push_front(i);
}
//pirnt(d);
cout << "====" << endl;
deque<int> d2;
//重載=賦值
d2 = d;
deque<int> d3;
d3.assign(d2.begin(), d2.end());
deque<int> d4;
d4.assign(10, 100);
pirnt(d4);
}
deque大小操作
deque.empty()
判斷容器是否為空deque.size()
返回容器中的元素個數deque.resize(num)
重新指定容器長度num,若容器邊長,則預設值填充新位置,若變短,刪除末尾元素deque.resize(num,elem)
重新指定容器長度num,若容器邊長,則elem填充新位置,若變短,刪除末尾元素
deque沒有容量概念
void pirnt(const deque<int> &d) {
for (deque<int>::const_iterator i = d.begin(); i != d.end(); i++) {
cout << *i << endl;
}
}
int main() {
//預設構造
deque<int> d;
for (int i = 0; i < 10; i++)
{
//尾部添加
//d.push_back(i);
//頭添加
d.push_front(i);
}
cout << d.empty() << endl;
cout << d.size() << endl;
d.resize(15, 6);
pirnt(d);
cout << "====" << endl;
d.resize(5);
pirnt(d);
}
deque插入刪除
兩端插入
push_back(e)
尾部添加epush_front(e)
頭部插入epop_back()
刪除最後的一個元素poh_front()
刪除第一個元素
指定位置插入
insert(pos,elem)
在pos位置插入elem元素的拷貝,返回新數據的位置insert(pos,n,elem)
在pos位置插入n個elem數據,無返回值insert(pos,beg,end)
在pos插入beg,end區間的數據,無返clear()
清空容器erase(beg,end)
刪除beg-end區間的數據,返回下一個數據的位置erase(pos)
刪除pos位置的數據,返回下一個數據的位置
int main() {
//預設構造
deque<int> d;
//尾部添加
d.push_back(1);
//頭添加
d.push_front(2);
//尾刪
d.pop_back();
//頭刪
d.pop_front();
//根據位置插入返回一個迭代器
deque<int>::iterator i = d.insert(d.begin(), 1);
//插入兩個10
d.insert(d.begin(), 2, 10);
//在頭部添加了容器中所有的元素
d.insert(d.begin(), d.begin(), d.end());
//從第二個刪到倒數第二個
deque<int>::iterator i2=d.erase(++d.begin(), --d.end());
//刪除第一個
d.erase(d.begin());
//清空
d.clear();
}
deque數據存取
at(int ind)
返回ind位置的數據operator[]
返回索引位置的數據front()
返回第一個元素back()
返回容器最後一個元素
int main() {
//預設構造
deque<int> d;
d.push_front(1);
d.push_front(2);
d.push_front(3);
d.push_front(4);
//重載[]符
cout << d[2] << endl;
//at獲取
cout << d.at(2) << endl;
//取第一個
cout << d.front() << endl;
//取最後一個
cout << d.back() << endl;
}
stack容器
棧容器,先進後出,只有頂端元素才能被使用,因此棧不允許有遍歷行為
stack構造
stack<T> stk
預設構造stack(const stack &stk)
; 拷貝構造
stack賦值
stack& operator=(const stack &stk)
重載=
stack數據存取
push(elem)
壓入一個元素pop()
彈出一個元素top()
獲取棧頂元素
stack大小
empty()
返回是否為空size()
返回棧大小
#include <stack>
using namespace std;
int main() {
stack<int> s;
//壓入一個元素
s.push(1);
s.push(2);
//拷貝構造
stack<int> s2(s);
//重載=賦值
stack<int> s3 = s2;
//是否為空
cout << s3.empty() << endl;
//彈出一個元素
s3.pop();
//棧大小
cout << s3.size() << endl;
//獲取棧頂元素
cout << s3.top() << endl;
}
queue容器
隊列,先進先出,只有頭尾能被外界訪問,因此沒有遍歷行為
queue構造
queue<T> que;
預設構造queue(const queue & q)
拷貝構造
queue賦值操作
queue& operator=(const queue &que)
重載=
queue數據存取
push(e)
隊尾添加一個元素pop()
隊頭移出第一個元素back()
返回最後一個元素front()
返回第一個元素
queue大小操作
empty()
返回是否為空size()
返回大小
#include <queue>
using namespace std;
int main() {
queue<int> q;
queue<int> q2(q);
queue<int> q3 = q2;
q3.push(1);
q3.push(2);
q3.pop();
cout << q3.front() << endl;
cout << q3.back() << endl;
cout << q3.size();
cout << q3.empty();
}
list容器
通過雙向鏈表實現,list的迭代器只支持前移和後移,屬於雙向迭代器
list構造
list<T> list
預設構造list(beg,end)
構造函數將beg-end區間元素拷貝給本身list(n,elem)
使用n個elem初始化本身list(const list &list)
拷貝構造
#include <iostream>
#include <list>
using namespace std;
int main() {
//預設構造
list<int> l;
//拷貝構造
list<int> l2(l);
//區間賦值
list<int> l3(l2.begin(), l2.end());
//使用4個5初始化
list<int> l4(4, 5);
}
list賦值和交換
assign(beg,end)
將beg-end區間數據拷貝給本身assign(n,m)
將n個m拷貝賦值給本身list& operatpr=(const list &list)
重載=swap(list)
交換
#include <iostream>
#include <list>
using namespace std;
int main() {
//預設構造
list<int> l;
l.assign(6, 1);
list<int> l2;
l2.assign(l.begin(), l.end());
//重載=
list<int> l3 = l2;
list<int> l4;
//交換
l4.swap(l3);
for (list<int>::iterator it = l4.begin(); it != l4.end(); it++) {
cout << *it << endl;
}
}
list大小操作
size()
返回容器中元素個數empty()
返回是否為空resize(n)
重新指定長度為n,如果邊長,則預設值填充新位置,變短則超出長度的元素被刪除resize(n,e)
重新指定長度為n,如果邊長,則e填充新位置,變短則超出長度的元素被刪除
int main() {
//預設構造
list<int> l;
l.assign(6, 1);
l.resize(10);
l.resize(15,7);
for (auto a : l)
{
cout << a ;
}
cout << l.size() << endl;
cout << l.empty() << endl;
}
list插入刪除
push_back(e)
尾部加入一個元素pop_back()
刪除容器中最後一個元素push_front(e)
頭部插入一個元素pop_front()
頭部刪除一個元素insert(pos,elem)
在pos位置插入elem元素的拷貝,返回新數據位置insert(pos,n,elem)
在pos位置插入n個elem,無返insert(pos,beg,end)
在pos位置插入beg-end區間數據,無返clear()
移除容器所有數據erase(beg,end)
移除beg-end區間數據,返回下一個數據的位置erase(pos)
移除pos位置數據,返回下一個元素的位置remove(elem)
刪除容器中所有和elem值匹配的元素
int main() {
//預設構造
list<int> l;
//尾部添加
l.push_back(1);
l.push_back(2);
l.push_back(3);
//刪除尾部
l.pop_back();
//刪除頭部
l.pop_front();
list<int> l2;
l2.insert(l2.begin(), 2);
l2.insert(l2.begin(), 2, 1);
l2.insert(l2.begin(), l.begin(), l.end());
l2.clear();
l2.erase(++l2.begin(), --l2.end());
l2.erase(l2.begin());
l2.remove(2);
}
list數據獲取
front()
返回第一個元素back()
返回最後一個元素
int main() {
//預設構造
list<int> l;
//尾部添加
l.push_back(1);
l.push_back(2);
l.push_back(3);
cout<<l.back();
cout << l.front();
}
list反轉和排序
因為list不支持隨機訪問,所以不能用自帶的sort排序
revers()
反轉鏈表sort()
鏈表排序 預設從小到大
bool a(int a,int b) {
return a > b;
}
int main() {
//預設構造
list<int> l;
//尾部添加
l.push_back(1);
l.push_back(4);
l.push_back(3);
l.reverse();
//如果想自定義排序規則,傳入方法a
l.sort(a);
cout<<l.back();
cout << l.front();
}
自定義數據類型排序
#include <iostream>
#include <list>
#include <string>
using namespace std;
class User {
public:
User() {
}
User(int _age, int _money, string _name):age(_age), money(_money), name(_name) {
}
int age;
int money;
string name;
};
bool a(User &a, User &b) {
if (a.age >= b.age) {
return a.money >= b.money;
}
return false;
}
int main() {
User u1 = { 18,600,"小明" };
User u2 = { 30,300,"小王" };
User u3 = { 20,400,"小周" };
list<User> l;
l.push_back(u1);
l.push_back(u2);
l.push_back(u3);
l.sort(a);
for (list<User>::iterator it = l.begin(); it != l.end(); it++) {
cout << it->age << "=" << it->money << "=" << it->name << endl;
}
}
set/multiset容器
所有元素都會在插入時自動被排序.set/multiset屬於關聯式容器,底層使用二叉樹實現
set和multiset區別:
- set不允許有重覆的元素,插入會返回插入結果和插入位置的迭代器
- multiset允許存在重覆的元素,返回插入只有插入位置的迭代器
set的構造和賦值
構造:
set<T> st
預設構造set(const set& st)
拷貝構造
賦值:
set& operator=(const set& set)
重載=
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s;
s.insert(1);
set<int> s2(s);
set<int> s3 = s2;
for (set<int>::iterator it = s3.begin(); it != s3.end(); it++) {
cout << *it << endl;
}
}
set容器大小和交換
size()
返回元素個數empty()
返回是否為空swap(st)
交換兩個集合容器
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s;
s.insert(1);
s.insert(1);
cout << s.empty() << endl;
cout << s.size() << endl;
set<int> s2;
s2.swap(s);
cout << s2.size() << endl;
}
set的插入刪除
insert(elem)
容器插入元素clear()
清空所有元素erase(pos)
刪除pos迭代器所指向的元素,返回下一個元素的迭代器erase(beg,end)
刪除區間beg-end的所有元素,返回下一個元素的迭代器erase(elem)
刪除容器中值為elem的元素
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s;
s.insert(1);
s.clear();
s.insert(2);
s.insert(3);
s.insert(4);
s.insert(5);
set<int>::iterator it1 = s.erase(s.begin());
set<int>::iterator it2 = s.erase(s.begin(), --s.end());
int a = s.erase(5);
}
set容器查找和統計
find(key)
查找元素是否存在,返回元素的迭代器,如果不存在返回set.end()count(key)
統計key的元素個數 在set中作用不大,因為不可重覆,要麼0要麼1
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s;
s.insert(1);
s.insert(2);
set<int>::iterator it=s.find(1);
if (it != s.end()) {
cout << "find!" << endl;
}
else {
cout << "null" << endl;
}
cout << s.count(1) << endl;
}
兩個set插入返回結果
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s;
pair<set<int>::iterator, bool> p = s.insert(1);
set<int>::iterator it = p.first;
cout << p.second << endl;
multiset<int> ms;
set<int>::iterator it2= ms.insert(1);
}
pair對組創建
成對出現的數據,利用對組可以返回兩個數據
pair<type,type p (v1,v2)
pair<type,type> p=make_pair(v1,v2)
#include <iostream>
#include <set>
using namespace std;
int main() {
pair<string, int> p("老王", 50);
cout << p.first << endl; //輸出第一個
cout << p.second << endl;//輸出第二個
pair<string, int> p2 = make_pair("小明", 15);
cout << p2.first << endl;
cout << p2.second << endl;
}
set容器排序
利用仿函數,修改排序規則
#include <iostream>
#include <set>
using namespace std;
class MyCompare {
public:
//這裡需要加const作用不知道,以後學了在回來解釋
bool operator() (int v1,int v2)const {
return v1 > v2;
}
};
int main() {
set<int,MyCompare> s;
s.insert(4);
s.insert(1);
s.insert(2);
s.insert(3);
for (set<int>::iterator it = s.begin(); it != s.end(); it++) {
cout << *it << endl;
}
}
自定義類型的排序
對於自定義的數據類型,必須指定排序規則才能插入
#include <iostream>
#include <set>
using namespace std;
class People {
public:
People(int _age) :age(_age) {
}
int age;
};
class MyCompare {
public:
// bool operator() (const People& v1,const People& v2)const
//只加& 就會報錯 必須加const修飾
bool operator() (People v1, People v2)const {
return v1.age > v2.age;
}
};
int main() {
set<People,MyCompare> s;
s.insert(People(1));
s.insert(People(4));
s.insert(People(6));
s.insert(People(2));
for (set<People>::iterator it = s.begin(); it != s.end(); it++) {
cout << it->age << endl;
}
}
map/multimap容器
- map的所有元素都是pair
- pair的第一個元素為key,起到索引作用,第二個元素的value
- 所有元素都會根據元素的鍵值自動排序
- map/multimap都屬於關聯式容器,底層是用二叉樹實現
- 可以根據key快速找到value
二者區別: map不允許存在相同的key,mulitmap可以存在
map構造和賦值
map<T1,T2> m
預設構造map(const map& m)
拷貝構造map& operator=(consst map& m)
重載=
#include <iostream>
#include <map>
using namespace std;
int main() {
map<int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(3, 30));
m.insert(pair<int, int>(4, 40));
map<int, int> m1(m);
map<int, int>m2 = m1;
for (map<int, int>::iterator it = m2.begin(); it != m2.end(); it++) {
cout << it->first << "===" << it->second << endl;
}
}
map大小和交換
size()
返回元素個數empty()
返回是否為空swap(m)
交換兩個map的元素
int main() {
map<int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(3, 30));
m.insert(pair<int, int>(4, 40));
map<int, int> m2;
m2.swap(m);
cout << m2.size() << endl;
cout << m2.empty() << endl;
}
map的插入和刪除
insert(elem)
容器插入元素clear()
清空元素erase(pos)
刪除pos迭代器指向的元素,返回下一個元素的迭代器erase(beg,end)
刪除區間beg-end的元素,返回下一個元素的迭代器erase(key)
根據key刪除元素
int main() {
map<int, int> m;
m.insert(pair<int, int>(1, 10));
m.clear();
m.insert(pair<int, int>(2, 20));
m.insert(make_pair(3, 30));
m.insert(map<int,int>::value_type(4,40));
//不要使用[]方式來獲取,因為如果沒有這個就會給你創建一個key為5,value為0的元素
m[5] = 50;
map<int, int>::iterator it = m.erase(m.begin());
map<int, int>::iterator it2 = m.erase(m.begin(), --m.end());
int deleted = m.erase(5);
cout << m.size();
}
map查找和統計
find(key)
查找key是否存在,返回元素的迭代器,不存在返回set.end()count(key)
統計key的個數,map中不是0就是1,在multimap中有用
int main() {
map<int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(make_pair(2, 20));
map<int,int>::iterator it=m.find(1);
cout << it->first<<"====" << it->second << endl;
cout << m.count(1) << endl;
}
int main() {
multimap<int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(make_pair(1, 20));
multimap<int,int>::iterator it=m.find(1);
cout << it->first<<"====" << it->second << endl;
it++;
cout << it->first<<"====" << it->second << endl;
cout << m.count(1) << endl;
}
map排序
利用仿函數,改變排序規則 兩個參數是key,根據key排
class MyR {
public :
bool operator()( int p1, int p2) const {
return p1>p2;
}
};
int main() {
multimap<int, int, MyR> m;
m.insert(pair<int, int>(1, 10));
m.insert(make_pair(2, 20));
m.insert(make_pair(4, 40));
m.insert(make_pair(3, 30));
for (map<int, int>::iterator it = m.begin(); it != m.end(); it++) {
cout << it->first << "==" << it->second << endl;
}
}
STL函數對象
函數對象
- 重載函數調用操作符的類,其對象稱為函數對象
- 函數對象使用重載的()時,行為類似函數的調用,也叫仿函數
- 函數對象(仿函數)是一個類,不是一個函數
函數對象的使用
- 函數對象使用可以像普通函數一樣,有參數和返回值
- 函數對象超出了普通函數的概念呢,函數對象可以有自己的狀態
- 函數對象可以作為參數
class MyR {
public :
bool v() {
this->count++;
return false;
}
bool operator()( int p1, int p2){
this->count++;
cout << "operator" << endl;
return p1<p2;
}
int count = 0;
};
int main() {
MyR mr;
mr(1, 2);
mr(1, 2);
mr(1, 2);
cout << mr.count << endl;
}
class MyR {
public :
bool v() {
this->count++;
return false;
}
bool operator()( int p1, int p2){
this->count++;
cout << "operator" << endl;
return p1<p2;
}
int count = 0;
};
void print(MyR & m,int a,int b) {
m(a, b);
}
int main() {
MyR mr;
print(mr, 1, 2);
}
謂詞
返回bool類型的仿函數稱為謂詞
如果operator接收一個參數,叫一元謂詞,兩個就叫二元謂詞
class MyR {
public :
bool operator()( int a){
return a>0;
}
};
int main() {
vector<int> v;
v.push_back(-1);
v.push_back(1);
v.push_back(3);
v.push_back(-2);
v.push_back(2);
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
vector<int>::iterator it2 = find_if(it, v.end(), MyR());
it = it2;
cout << *it2 << endl;
}
}
class MyR {
public :
bool operator()( int a,int b){
return a<b;
}
};
int main() {
vector<int> v;
v.push_back(-1);
v.push_back(1);
v.pu