為什么使用模板:
C++重載(overloading),重載函數一般含有不同的參數個數或不同的參數類型。如果使用MAX函數對不同類型的求最大值,就要定義不同的重載函數:
int max(int x,int y) { if(x>y) return x; else return y; } float max(float x,float y) { if(x>y) return x; else return y; }
但是如果要用double型,又需要重新定義。。。
模板就是為了解決重載函數定義不全的問題,它可以實現類型參數化,即把類型定義為參數,從而實現代碼的可重用性。模板分為兩類:函數模板和類模板
函數模板:
Template<class 或 typename T>
template是一個聲明的模板的關鍵字,表示聲明一個模板關鍵字class不能省。
template <class T> T min(T x,T y) { return(x<y)?x:y; }
類模板定義:
template <class T>
class 類名{
};
template <class T1,class T2> class student{ T1 a; T2 b; public: student(T1 a,T2 b);//constructor void show(); }; template<class T1, class T2> student<T1,T2>::student(T1 a,T2 b):a(a),b(b){} template<class T1,class T2> void student<T1,T2>::show() { cout<<a<<b<<endl; } int main() { student<char ,char> s('a','b'); s.show(); return 0; }
把類的屬性定義為private,保護數據,不能外部隨意訪問,但是可以定義一個訪問內部數據的函數接口。也可以定義一個修改內部屬性的函數(那這與外部訪問數據和修改數據有什么區別,這樣可以在修改函數里加各種限制。哈哈)
array < int > a(10);
array < int >表明用int類型來代替模板類中的類參數“T”,編譯器會將模板類array中所有的類參數T都用int來代替。例如類中的私有成員變量“T * num;”會被替換為“int * num;”。對類中的成員函數也會進行相同的替換,如“T & operator[]( int );”將會被替換為“int & operator[]( int );”。
using namespace std; template< class T > class array { public: array( int ); T & operator[]( int );//操作符[]取第int個數,返回類型為T。。 const T & operator[] ( int )const; int getlen() const { return length; } ~array(); private: array(){}; int length; T * num; }; template < class T > array< T >::array( int n ) { num = new T[n]; length = n; } template < class T > array< T >::~array() { delete[] num; } template< class T > T & array< T > ::operator[] ( int i ) { if( i < 0 || i >= length ) throw string( "out of bounds" ); return num[i]; } template< class T > const T & array< T > ::operator[] (int i) const { if( i < 0 || i >= length) throw string( "out of bounds" ); return num[i]; } template< class T > ostream & operator<<( ostream & out, const array <T> & A ) { for(int i=0; i < A.getlen(); i++) out<< A[i] << " "; return out; } int main() { array< int > A(10); for(int i = 0; i < 10; i++) { A[i] = 2*i; } cout<<A<<endl; return 0; }
C++編程技巧:對象與實例的區別,new與不用new的區別:
class A a; a 在棧里;
class A a=new A; A 在堆里;
new創建類對象需要指針接收,一處初始化,多處使用; CTest* p= new CTest();//new申請的對象,則只有調用到delete時再會執行析構函數 ; 不用new CTest mTest;//不需要手動釋放,該類析構函數會自動執行
new需要delete銷毀
new創建對象在堆空間
頻繁調用不適合用new,要申請和釋放內存
用new 生成對象,上面的例子寫為:
int main() { student<char ,char>* s=new student<char ,char >('a','b'); s->show(); delete(s); return 0; }
(java中不同:JAVA:
A a = new A();
為A對象創建了一個實例,但在內存中開辟了兩塊空間:一塊空間在堆區,存放new A()這個對象;
另一塊空間在堆棧,也就是棧,存放a,a的值為new A()這個對象的內存地址。因為java在JVM中運行,
所以a 描述的內存地址不一定是這個對象真實內存的地址。
Object o; // 這是聲明一個引用,它的類型是Object,他的值為null,還沒有指向任何對象,該引用放在內存的棧區域
o = new Object(); // new Object()句,實例化了一個對象,就是在堆中申請了一塊連續空間用來存放該對象。
= // 運算符,將引向o指向了對象。也就是說將棧中表示引用o的內存地址的內容改寫成了Object對象在堆中的地址。
創建對象:student stu1 = new student();
通常把這條語句的動作稱之為創建一個對象,其實,它包含了四個動作。
1)右邊的"new student",是以student類為模板,在堆空間里創建一個student類的對象(也簡稱為student對象)。
2)末尾的()意味着,在對象創建后,立即調用student類的構造函數,對剛生成的對象進行初始化。
構造函數是肯定有的。如果你沒寫,Java會給你補上一個默認的構造函數。
3)左邊的"student stu1"創建了一個student類引用變量。所謂student類引用,就是以后可以用來指向某個
student對象的對象引用,它指向的是某個student對象的內存地址(有點C語言中指針的味道)。
4)"="操作符使對象引用指向剛創建的那個student對象。
我們可以把這條語句拆成兩部分:student stu1; (1)
stu1 = new student(); (2)
效果是一樣的。
)
C++ 如果直接定義類,如classA a; a 存在棧上(也意味着復制了對象a在棧中),如果classA a = new classA就存在堆
非類型模板參數:
C++中:
Student student(20) ; //這里student是引用 對象分配在 棧空間中,這里只是我的理解
Student *student = new Student(20); //這里student是指針,new Student(20)是分配在堆內存空間的
- Student stu;//對象 stu 在棧上分配內存,需要使用
&
獲取它的地址 - Student *pStu = &stu;//創建對象指針
在堆上創建對象,這個時候就需要使用前面講到的new
關鍵字
- Student *pStu = new Student;
在棧上創建出來的對象都有一個名字,比如 stu,使用指針指向它不是必須的。但是通過 new 創建出來的對象就不一樣了,它在堆上分配內存,沒有名字,只能得到一個指向它的指針,所以必須使用一個指針變量來接收這個指針,否則以后再也無法找到這個對象了,更沒有辦法使用它。也就是說,使用 new 在堆上創建出來的對象是匿名的,沒法直接使用,必須要用一個指針指向它,再借助指針來訪問它的成員變量或成員函數。棧內存是程序自動管理的,不能使用 delete 刪除在棧上創建的對象;堆內存由程序員管理,對象使用完畢后可以通過 delete 刪除。在實際開發中,new 和 delete 往往成對出現,以保證及時刪除不再使用的對象,防止無用內存堆積。
new A以及new A()的區別:
調用new分配的內存有時候會被初始化,而有時候不會,這依賴於A的類型是否是POD(Plain old data)類型,或者它是否是包含POD成員、使用編譯器生成默認構造函數的類。POD class沒有用戶定義的析構函數、拷貝構造函數和非靜態的非POD類型的數據成員。沒有用戶定義的構造函數,沒有私有的或者保護的非靜態數據,沒有基類或虛函數。它只是一些字段值的集合,沒有使用任何封裝以及多態特性。
#include <iostream> using namespace std; struct A { int m; }; // POD struct B { ~B(){}; int m; }; // non-POD, compiler generated default ctor struct C { C() : m() {}; ~C(){}; int m; }; // non-POD, default-initialising m int main() { A *aObj1 = new A; A *aObj2 = new A(); cout << aObj1->m << endl; cout << aObj2->m << endl; B *bObj1 = new B; B *bObj2 = new B(); cout << bObj1->m << endl; cout << bObj2->m << endl; C *cObj1 = new C; C *cObj2 = new C(); cout << cObj1->m << endl; cout << cObj2->m << endl; delete aObj1; delete aObj2; delete bObj1; delete bObj2; delete cObj1; delete cObj2; return 0; }
new A:不確定的值
new A():value-initialize A,由於是POD類型所以是zero initialization
new B:默認構造(B::m未被初始化)
new B():value-initialize B,zero-initialize所有字段,因為使用的默認構造函數
new C:default-initialize C,調用默認構造函數
new C():value-initialize C,調用默認構造函數
在所有C++版本中,只有當A是POD類型的時候,new A和new A()才會有區別。而且,C++98和C++03會有區別。
但是在Java中
Student student(20) ; //注意:java中沒有這樣實例化對象的, 要想得到一個對象 必須要new出來.
Student student ; //這個只是定義了一個引用 ,沒有指向任何對象
Student student = new Student(20); //定義了一個引用,指向堆內存中的student對象
常數,或指向外部鏈接對象的指針。
template <class T,MAXSIZE> class Stack{ T elemsp[MAXSIZE]; }; Stack<int, 20> intStack; Stack<int ,10> intStack2;