閱讀C++原始碼必備
1,預處理指令
C++的預處理(Preprocess),是指在C++程式原始碼被編譯之前,由前處理器(Preprocessor)對C++程式原始碼進行的處理。這個過程並不對程式的原始碼進行解析,但它把源代分割或處理成為特定的符號用來支援巨集調呼叫。
常用指令:
#include 包含標頭檔案
#if 條件 #else 否則 #elif 否則如果 #endif 結束條件 #ifdef 或 #if defined 如果定義了一個符號, 就執行操作 #ifndef 或 #if !defined 如果沒有定義一個符號,就指執行操作 #define 定義一個符號 #undef 刪除一個符號 #line 重新定義當前行號和檔名 #error 輸出編譯錯誤 訊息, 停止編譯 #pragma 提供 機器專用的特性,同時保證與C++的完全相容2,模板用法 :
template:酷勤
1. 模板的概念。
我們已經學過過載(Overloading),對過載函式而言,C++的檢查機制能通過函式引數的不同及所屬類的不同。正確的呼叫過載函式。例如,為求兩個數的最大值,我們定義MAX()函式需要對不同的資料型別分別定義不同過載(Overload)版本。
//函式1.
int max(int x,int y);
{return(x>y)?x:y ;}
//函式2.
float max( float x,float y){
return (x>y)? x:y ;}
//函式3.
double max(double x,double y)
{return (c>y)? x:y ;}
但如果在主函式中,我們分別定義了 char a,b; 那麼在執行max(a,b);時 程式就會出錯,因為我們沒有定義char型別的過載版本。
現在,我們再重新審視上述的max()函式,它們都具有同樣的功能,即求兩個數的最大值,能否只寫一套程式碼解決這個問題呢?這樣就會避免因過載函式定義不 全面而帶來的呼叫錯誤。為解決上述問題C++引入模板機制,模板定義:模板就是實現程式碼重用機制的一種工具,它可以實現型別引數化,即把型別定義為引數, 從而實現了真正的程式碼可重用性。模版可以分為兩類,一個是函式模版,另外一個是類模版。
2. 函式模板的寫法
函式模板的一般形式如下:
Template <class或者也可以用typename T>
返回型別 函式名(形參表)
{//函式定義體 }
說明: template是一個宣告模板的關鍵字,表示宣告一個模板關鍵字class不能省略,如果型別形參多餘一個 ,每個形參前都要加class <型別 形參表>可以包含基本資料型別可以包含類型別.
請看以下程式:
//Test.cpp
#include <iostream>
using std::cout;
using std::endl;
//宣告一個函式模版,用來比較輸入的兩個相同資料型別的引數的大小,class也可以被typename代替,
//T可以被任何字母或者數字代替。
template <class T>
T min(T x,T y)
{ return(x<y)?x:y;}
void main( )
{
int n1=2,n2=10;
double d1=1.5,d2=5.6;
cout<< "較小整數:"<<min(n1,n2)<<endl;
cout<< "較小實數:"<<min(d1,d2)<<endl;
system("PAUSE");
}
程式執行結果:
程式分析:main()函式中定義了兩個整型變數n1 , n2 兩個雙精度型別變數d1 , d2然後呼叫min( n1, n2); 即例項化函式模板T min(T x, T y)其中T為int型,求出n1,n2中的最小值.同理呼叫min(d1,d2)時,求出d1,d2中的最小值.
3. 類别範本的寫法
定義一個類别範本:
Template < class或者也可以用typename T >
class類名{
//類定義......
};
說明:其中,template是宣告各模板的關鍵字,表示宣告一個模板,模板引數可以是一個,也可以是多個。
例如:定義一個類别範本:
// ClassTemplate.h
#ifndef ClassTemplate_HH
#define ClassTemplate_HH
template<typename T1,typename T2>
class myClass{
private:
T1 I;
T2 J;
public:
myClass(T1 a, T2 b);//Constructor
void show();
};
//這是建構函式
//注意這些格式
template <typename T1,typename T2>
myClass<T1,T2>::myClass(T1 a,T2 b):I(a),J(b){}
//這是void show();
template <typename T1,typename T2>
void myClass<T1,T2>::show()
{
cout<<"I="<<I<<", J="<<J<<endl;
}
#endif
// Test.cpp
#include <iostream>
#include "ClassTemplate.h"
using std::cout;
using std::endl;
void main()
{
myClass<int,int> class1(3,5);
class1.show();
myClass<int,char> class2(3,"a");
class2.show();
myClass<double,int> class3(2.9,10);
class3.show();
system("PAUSE");
}
最後結果顯示:
一般來說,非型別模板引數可以是常整數(包括列舉)或者指向外部連結物件的指標。
那麼就是說,浮點數是不行的,指向內部連結物件的指標是不行的。
template<typename T, int MAXSIZE>
class Stack{
Private:
T elems[MAXSIZE];
…
};
Int main()
{
Stack<int, 20> int20Stack;
Stack<int, 40> int40Stack;
…
};
C++程式語言中的模板應用在一定程度上大大提高了程式開發的效率。我們在這篇文章中為大家詳細講解一下有關C++模板的基本概念,希望初學者們可以通過本文介紹的內容充分掌握這方面的知識。
前段時間重新學習C++,主要看C++程式設計思想和C++設計新思維。對模版的使用有了更進一層的瞭解,特總結如下:
下面列出了C++模板的常用情況:
1. C++模板類靜態成員
- template < typename T> struct testClass
- {
- static int _data;
- };
- template< > int testClass< char>::_data = 1;
- template< > int testClass< long>::_data = 2;
- int main( void ) {
- cout < < boolalpha < < (1==testClass< char>::_data) < < endl;
- cout < < boolalpha < < (2==testClass< long>::_data) < < endl;
- }
2. C++模板類偏特化
- template < class I, class O> struct testClass
- {
- testClass() { cout < < "I, O" < < endl; }
- };
- template < class T> struct testClass< T*, T*>
- {
- testClass() { cout < < "T*, T*" < < endl; }
- };
- template < class T> struct testClass< const T*, T*>
- {
- testClass() { cout < < "const T*, T*" < < endl; }
- };
- int main( void )
- {
- testClass< int, char> obj1;
- testClass< int*, int*> obj2;
- testClass< const int*, int*> obj3;
- }
3.類模版+函式模版
- template < class T> struct testClass
- {
- void swap( testClass< T>& ) { cout < < "swap()" < < endl; }
- };
- template < class T> inline void swap( testClass< T>& x,
testClass< T>& y )- {
- x.swap( y );
- }
- int main( void )
- {
- testClass< int> obj1;
- testClass< int> obj2;
- swap( obj1, obj2 );
- }
4. 類成員函式模板
- struct testClass
- {
- template < class T> void mfun( const T& t )
- {
- cout < < t < < endl;
- }
- template < class T> operator T()
- {
- return T();
- }
- };
- int main( void )
- {
- testClass obj;
- obj.mfun( 1 );
- int i = obj;
- cout < < i < < endl;
- }
5. 預設C++模板引數推導
- template < class T> struct test
- {
- T a;
- };
- template < class I, class O=test< I> > struct testClass
- {
- I b;
- O c;
- };
- void main()
- {
- }
6. 非型別C++模板引數
- template < class T, int n> struct testClass {
- T _t;
- testClass() : _t(n) {
- }
- };
- int main( void ) {
- testClass< int,1> obj1;
- testClass< int,2> obj2;
- }
7. 空模板引數
- template < class T> struct testClass;
- template < class T> bool operator==( const testClass< T>&,
const testClass< T>& )- {
- return false;
- };
- template < class T> struct testClass
- {
- friend bool operator== < >
( const testClass&, const testClass& );- };
- void main()
- {
- }
8. template template 類
- struct Widget1
- {
- template< typename T>
- T foo(){}
- };
- template< template< class T>class X>
- struct Widget2
- {
- };
- void main()
- {
- cout< < 3 < < '\n';
- }
以上就是對C++模板的一些常用方法的介紹。
3,typedef
http://www.cnblogs.com/SweetDream/archive/2006/05/10/395921.html
C/C++語言中的typedef相信大家已經不陌生,本文對C/C++語言關鍵字typedef的各種用法作一個介紹。
typedef,顧名思義,為“型別定義”,可以解釋為:將一種資料型別定義為某一個識別符號,在程式中使用該識別符號來實現相應資料型別變數的定義。例如:
typedef unsigned int UINT;
int main (int argc, char *argv[])
{
unsigned int a; // it’s OK
UINT b; // it’s OK, a and b are of the same type (int)
// . . . // code references the symbol a and b
return 0;
}
上面的程式碼中,a和b屬於同一種資料型別(unsigned int型),因為UINT識別符號已經標示為unsigned int型別。上面的程式碼看似簡單,相信很多讀者都用過這種方法,但這絕不是typedef的全部,下面介紹使用typedef定義複雜資料型別的幾種用法。
1、 定義結構體型別
結構體是一種較為常見的資料型別,在C/C++程式設計中使用的非常廣泛。下面的程式碼就是結構體型別的一個應用:
#include <iostream.h>
int main (int argc, char *argv[])
{
struct {int x; int y;} point_a, point_b;
point_a.x = 10; point_a.y = 10;
point_b.x = 0; point_b.y = 0;
ios::sync_with_stdio();
cout << point_a.x + point_a.y << endl;
cout << point_b.x + point_b.y << endl;
return 0;
}
上面的程式碼包含了兩個結構體變數:point_a和point_b,它們的資料型別相同,都是struct {int x; int y;}型別。這種說法可能有點彆扭,習慣上說point_a和point_b都是結構體型別,為什麼偏偏要說是struct {int x; int y;}型別呢?因為這種說法更加精確。比如在第一個例子中,對於“unsigned int a, b;”這條語句,我們可以說a和b都是整數型別,但更精確地說,它們應該是unsigned int型別。
既然struct {int x; int y;}是一種自定義的複雜資料型別,那麼如果我們要定義多個struct {int x; int y;}型別的變數,應該如何編寫程式碼呢?其實很簡單,就當struct {int x; int y;}是一個簡單資料型別就可以了:
struct {int x; int y;} var_1; // 定義了變數var_1
struct {int x; int y;} array_1 [10]; // 定義了陣列array_1
struct {struct{int x; int y;} part1; int part2;} cplx;
上面的第三行定義了一個cplx變數,它的資料型別是一個複雜的結構體型別,有兩個成員:part1和part2。part1是struct {int x; int y;}型別的,part2是int型別的。
從上面的例子可以看出,如果在程式中需要多處定義struct {int x; int y;}型別的變數,就必須多次輸入“struct {int x; int y;}”這一型別名稱,況且,如果在結構體中有某個成員是struct {int x; int y;}型別的,還會使得定義變得非常繁雜而且容易出錯。為了輸入程式的方便,同時為了增強程式的可讀性,我們可以把struct {int x; int y;}這一資料型別定義為識別符號“Point”,那麼上面的程式就會變得更容易理解:
typedef struct {int x; int y;} Point;
Point var_1; // 定義了變數var_1
Point array_1 [10]; // 定義了陣列array_1
struct {Point part1; int part2;} cplx; // 定義了複雜型別變數cplx
需要說明的是,我們還可以使用下面的方法來定義結構體變數:
struct t_Point {
int x; int y;}; // 注意,這裡最後一個分號不能省略
int main(int argc, char* argv[])
{
struct t_Point a, b;
// . . .
return 0;
}
顯然,這種方法沒有typedef更加直觀(在C++中,main函式第一行的struct關鍵字可以省略,但在標準C中,省略該關鍵字會出現編譯錯誤)。
此外,對於定義連結佇列中的結點,我們可以這樣實現:
typedef struct t_node {
int Value;
struct t_node *next;
} Node;
當然也可以這樣定義:
typedef strcut t_node Node;
struct t_node {
int Value;
Node *next;
};
2、定義陣列型別
與定義結構體型別相似,可以使用typedef來定義陣列型別,例如:
typedef int MyIntArray [100];
那麼程式中的
MyIntArray ia;
就相當於
int ia[100];
3、 定義函式指標
看下面的程式碼:
typedef void (*FUNCADDR)(int)
此處FUNCADDR是指向這樣一個函式的指標,該函式的返回值為void型別,函式有一個int型的引數。再例如:
void print (int x)
{
printf (“%d\n”, x);
}
int main (int argc, char *argv[])
{
FUNCADDR pFunc;
pFunc = print; // 將指標指向print函式
(*pFunc)(25); // 呼叫函式print
return 0;
}
函式指標一般用於回撥函式、中斷處理過程的宣告,以及在物件導向程式設計中對事件處理過程的宣告。
4、 定義類型別
類是物件導向程式設計語言中引入的一種新的資料型別,既然是資料型別,就可以使用typedef對其進行定義:
typedef class {
private:
int a;
public:
int b;
} MyClass;
其實這和定義結構體型別非常相似,不過很少有人這麼使用。
相關文章
- iOS Tagged Pointer (原始碼閱讀必備知識)iOS原始碼
- 【原始碼閱讀】AndPermission原始碼閱讀原始碼
- 【原始碼閱讀】Glide原始碼閱讀之with方法(一)原始碼IDE
- 【原始碼閱讀】Glide原始碼閱讀之into方法(三)原始碼IDE
- ReactorKit原始碼閱讀React原始碼
- AQS原始碼閱讀AQS原始碼
- CountDownLatch原始碼閱讀CountDownLatch原始碼
- HashMap 原始碼閱讀HashMap原始碼
- delta原始碼閱讀原始碼
- 原始碼閱讀-HashMap原始碼HashMap
- NGINX原始碼閱讀Nginx原始碼
- Mux 原始碼閱讀UX原始碼
- HashMap原始碼閱讀HashMap原始碼
- fuzz原始碼閱讀原始碼
- RunLoop 原始碼閱讀OOP原始碼
- express 原始碼閱讀Express原始碼
- muduo原始碼閱讀原始碼
- stack原始碼閱讀原始碼
- 【原始碼閱讀】Glide原始碼閱讀之load方法(二)原始碼IDE
- PostgreSQL 原始碼解讀(3)- 如何閱讀原始碼SQL原始碼
- JDK原始碼閱讀:Object類閱讀筆記JDK原始碼Object筆記
- Laravel 原始碼閱讀 - QueueLaravel原始碼
- Vollery原始碼閱讀(—)原始碼
- 使用OpenGrok閱讀原始碼原始碼
- 如何閱讀Java原始碼?Java原始碼
- buffer 原始碼包閱讀原始碼
- 原始碼閱讀技巧篇原始碼
- 如何閱讀框架原始碼框架原始碼
- 再談原始碼閱讀原始碼
- Laravel 原始碼閱讀 - EloquentLaravel原始碼
- 如何閱讀jdk原始碼?JDK原始碼
- express 原始碼閱讀(全)Express原始碼
- Vuex原始碼閱讀分析Vue原始碼
- React原始碼閱讀:setStateReact原始碼
- ArrayList原始碼閱讀(增)原始碼
- ThreadLocal原始碼閱讀thread原始碼
- snabbdom 原始碼閱讀分析原始碼
- koa原始碼閱讀[0]原始碼