C++:随笔9----模板/内联函数/容器
C++設計范型:(到目前為止已經學習了兩種C++設計范型)
(1)面向過程:按照面向過程式范型吧程序劃分成不同的函數。
(2)面向對象:按照面向對象式范型把代碼和數據組織成各種各樣的類,并建立類之間的繼承關系。
另一種范型:范型編程。
(3)泛型編程:泛型編程技術支持程序員創建函數和類的藍圖(即模板,template),而不是具體的函數和類。
?
PS:關鍵字class并不意味著這個是個類,這只是一種約定俗成的寫法。在告訴計算機T是一種類型之后,就可以像對待一種普通數據類型那樣使用他了。(寫法是先寫template<class T>接下來寫要使用的函數模板的原型)
實現a和b兩個地址的交換,也就是實現了傳進來的兩個參數值的交換。
?
例子:(函數模板)
#include<iostream>
#include<string>template<class T>
void swap(T &a,T &b)
{T tmp=a;//設置一個中間變量a=b;b=tmp;
}
int main()
{ int i1=3;int i2=4;std::cout<<“交換前i1=”<<i1<",i2="<<i2<<std::endl;swap(i1,i2);//這種是傳引用調用,我們傳給他i1,i2,用一個&指針去引用他i1的地址std::cout<<“交換后i1=”<<i1<",i2="<<i2<<std::endl;std::string1 s1="我們";std::string2 s2=“他們”;std::cout<<“交換前s1=”<<s1<",s2="<<s2<<std::endl;swap(s1,s2);//這種是傳引用調用,我們傳給他i1,i2,用一個&指針去引用他i1的地址std::cout<<“交換后s1=”<<s1<",s2="<<s2<<std::endl;return 0;
}
PS:??
因為我們在調用類型過程中已經知道他要用什么類型的值了,如果是int整型就在<>尖括號里邊寫int,如果是double類型就在<>尖括號里邊寫double。但是如果你要寫傳統的方式也行,像普通函數調用兩個尖括號<>不用寫也是可以的。但是如果我們強調說我們調用的是一個函數模板我們可以這樣子加上<>尖括號帶一個數據類型。
---------類模板:(涉及到類的就是高級的東西)
?具體的操作替換T,這里T只是一個占位符。
棧(stack):棧是限制僅在表的一端進行插入和刪除運算的線性表,通常稱插入和刪除的一端為棧頂(top),另一端為棧底(bottom),當表中沒有元素時稱空棧。
例如我們每當調用一個函數和方法的時候,編譯器就會使用一個棧來傳遞輸入參數,首先他壓入的是一個它的返回值,然后壓入參數。
??
用類模板的方式寫一個棧的程序:
#include<iostream>
#include<string>
template<class T>//定義一個類模板
class Stack
{
public:Stack(unsigned int size = 1000);//構造函數(最好給他一個參數)~Stack();//析構函數void push(T value);//方法(是把一個value給推進棧)//value是作為push的一個參數,不需要把他作為一個成員T pop();//(把棧里邊的數據給推出來,不需要參數,但是需要返回值,不知道類型用T占位符)
private:unsigned int size;//私有成員,表示棧的尺寸unsigned int sp;//sp是棧指針(比如說我push進去了兩個,要知道我現在push進去的元素在棧的第幾個,要知道他的sp這個值指向的是哪一個,它指向b那我們就知道這個c是在b之上的,因為有這個指針才知道現在的狀態)T *data;//棧的數據(data存放棧的數據)
};
//下面是對類的實現
template<class T>
Stack<T>::Stack(unsigned int size)//實現構造器(傳進去參數size如果沒有值就默認為100)
{this->size = size;//this->size就是類的成員中的size。后邊的size就是傳進來的參數size。用來表示我們這個棧有多大data = new T(size);//對棧進行初始化。我們就用new指針,new一個T類型,我們不知道是什么類型,在實際的調用過程中才知道,我們在整個模板類的整個聲明和定義中都用T占位符來表示一種類型,雖然不知道它的類型是什么,但是我們知道它的大小是size。sp = 0;//sp默認是0
}
template<class T>
Stack<T>::~Stack()//析構器
{delete[]data;//析構器就是刪除內存,這里是刪除數組(動態的刪除數組)
}
template <class T>
void Stack<T>::push(T value)
{data[sp++] = value;//0存放完之后再++
}
template<class T>
T Stack<T>::pop()//他的返回值是T,就是將當前sp指針,指向的這個棧的數據給彈回來(先--再sp)
{return data[--sp];//data是一個數組
}
int main()
{Stack<int> intStack(100);intStack.push(1);intStack.push(2);intStack.push(3);//推123進去std::cout << intStack.pop() << std::endl;std::cout << intStack.pop() << std::endl;std::cout << intStack.pop() << std::endl;//打印出來是321return 0;
}
結果見上右圖。
---------內聯(inline)函數以及創建內聯模板
有點類似于宏替換,把函數體替換到要調用處的函數名里邊去。也就是說函數分為ABC三個函數,然后main函數來調用,如果說A是inline函數的話,那么他不通過普通調用函數的方式來調用,他會把整個A函數放到main函數調用它的這塊地方,把它放到源代碼里邊去。
?
?
把上邊的程序進行改寫:(類的內聯,我們自己給他寫進去,不用加inline)
#include<iostream>
#include<string>
template<class T>//定義一個類模板
class Stack
{
public:Stack(unsigned int size = 1000)//構造函數(最好給他一個參數){this->size = size;data = new T(size);sp = 0;}~Stack()//析構函數{delete[]data;}void push(T value){data[sp++] = value;//0存放完之后再++}T pop(){return data[--sp];//data是一個數組}
private:unsigned int size;unsigned int sp;T *data;
};
int main()
{Stack<int> intStack(100);intStack.push(1);intStack.push(2);intStack.push(3);//推123進去std::cout << intStack.pop() << std::endl;std::cout << intStack.pop() << std::endl;std::cout << intStack.pop() << std::endl;//打印出來是321return 0;
}
運行結果同上。(前邊是按照傳統的范式來寫的,但是建議類的模板使用內聯的方式,把定義過程直接寫進來)
?
--------容器
上邊的基于一個模板的stack類就是一個容器,它是一個棧容器。
?
?
例子:
#include<iostream>
#include<string>
#include<vector>
int main()
{ std::vector < std::string > names;//把這個向量vector的名字叫做namesnames.push_back("我");//往里邊添加成員names.push_back("你");for (int i = 0; i < names.size(); i++)//知道他有多少個元素我們調用它的size()方法就可以了{std::cout << names[i] << std::endl;//可以使用像數組的方式來對它進行訪問}return 0;
}
--------迭代器
??
使用迭代器完成相應的遍歷:
#include<iostream>
#include<string>
#include<vector>
int main()
{ std::vector < std::string > names;//把這個向量vector的名字叫做namesnames.push_back("我");//往里邊添加成員names.push_back("你");//每一個容器里邊都會提供一個迭代器,迭代器的名字都一樣iterator//begin指向的是數據的起始位置,end是指向的是它最后一個元素的下一個位置,也就是他這個容器的底步std::vector<std::string>::iterator iter = names.begin();//定義一個叫iter的迭代器,begin()就是他的開始位置(這里就是對申請的iter這個迭代器進行初始化,初始化我們調用了這個向量的begin方法,這個方法是返回他的開始位置的值)//使用一個while循環while (iter != names.end())//注意while的條件(names.end()是向量的最后一個元素的下一個位置,是他的底步(指向最下一個元素的底步(不是指向最下面的一個元素))){std::cout << *iter << std::endl;//這個迭代器是一個智能指針,一個特殊的指針我們用*取他的值++iter;//然后++指向下一個元素}return 0;}
排序sort();函數
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
int main()
{ std::vector < std::string > names;//把這個向量vector的名字叫做namesnames.push_back("I");names.push_back("we");//往里邊添加成員names.push_back("you");names.push_back("he");names.push_back("she");std::sort(names.begin(), names.end());//排序std::vector<std::string>::iterator iter = names.begin();while (iter != names.end()){std::cout << *iter << std::endl;++iter;}return 0;}
?
總結
以上是生活随笔為你收集整理的C++:随笔9----模板/内联函数/容器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++:随笔8---命名空间
- 下一篇: (曲率系列2:)Paper6:Curva