C++基礎
定義常量的兩種簡單方式:const和#define
C++的修飾符類型有signed, unsigned, long, short
C++程序中可用的存儲類:auto、static、extern、mutable、thread_local
auto關鍵字用于兩種情況:
1、聲明變量時根據初始化表達式自動推斷該變量的類型
2、聲明函數時函數返回值的占位符
auto f = 3.14; //double
auto s("hello"); //const char*
auto z = new auto(9); //int*
auto x1 = 5, x2 = 5.0, x3 = 'r'; //錯誤,必須是初始化為同一類型
static存儲類指示編譯器在程序的生命周期內保持局部變量的存在,而不需要在每次它進入和離開作用域時進行創建和銷毀。因此,使用static修飾全局變量時,會使變量的作用域限制在聲明它的文件內。
在C++中,當static用在類數據成員上時,會導致僅有一個該成員的副本被類的所有對象共享。
extern存儲類用于提供一個全局變量的引用,全局變量對所有的程序文件都是可見的。當您使用‘extern’時,對于無法初始化的變量,會把變量名指向一個之前定義過的存儲位置。
當您有多個文件且定義了一個可以在其他文件中使用的全局變量或函數時,可以在其他文件中使用extern來得到已定義的變量或函數的引用。可以這么理解,extern是用來在另一個文件中聲明一個全局變量或函數。
// main.cpp
#include <iostream>
int count;
extern void write_extern();
int main()
{
count = 5;
write_extern();
return 0;
}
//support.cpp
#include <iostream>
extern int count;
void write_extern(void){std::cout<<"Count is"<<count<<std::endl;}
g++ main.cpp support.cpp -o write
mutable存儲類只能用于類的數據成員,不能用于普通變量。具有mutable性質的類的數據成員打破了類對象的const限定,允許修改類的mutable的數據成員,即便類的其他成員仍然是const只讀屬性。
thread_local存儲類:使用thread_local說明符聲明的變量盡可在它在其上創建的線程上訪問。變量在創建線程時創建,并在銷毀線程時銷毀。每個線程都有其自己的變量副本。
thread_local說明符可以與static或extern合并。
可以將thread_local僅用于數據聲明和定義,thread_local不能用于函數聲明或定義。
C++運算符:算術運算符、關系運算符、邏輯運算符、位運算符、賦值運算符、雜項運算符
位運算符:&、|、^、~、<<
雜項運算符:sizeof、Condition? X:Y、逗號、cast、
逗號運算符:使用逗號運算符是為了把幾個表達式串在一起,整個逗號表達式的值是以逗號分隔的列表中的最后一個表達式的值。
var = (count=19, incr=10, count+1);
C++循環:while、for、范圍for、do...while、嵌套循環
判斷語句:if, if...else, 嵌套if, switch, 嵌套switch語句
#include <iostream>
using namespace std;
int main()
{
char grade = 'D';
switch(grade)
{
case 'A':
cout << "很棒!"<<endl;
break;
case 'C':
cout << "做得好!"<< endl;
break;
default:
cout << "無效的成績"<< endl;
}
return 0;
}
函數的引用調用:向函數傳遞參數的引用調用方法,把參數的地址復制給形式參數。在函數內,該引用用于訪問調用中要用到的實際參數。這意味著,修改形式參數會影響實際參數。
#include <iostream>
void swap(int &x, int &y){int temp = x; x=y; y=temp;}
int main()
{
int a = 100; int b = 200;
cout << "交換前,a的值:"<< a << endl;
cout <<"交換前, b的值:"<< b << endl;
swap(a,b);
cout << "交換后,a的值:"<< a << endl;
cout <<"交換后, b的值:"<< b << endl;
return 0;
}
參數的默認值:當您定義一個函數,您可以為參數列表中后邊的每個參數指定默認值。當調用參數時,如果實際參數的值留空,則使用這個默認值。
Lambda表達式把函數看作對象。Lambda表達式可以像對象一樣使用,比如可以將它們賦給變量和作為參數傳遞,還可以像函數一樣對其求值。
[](int x, int y){return x<y;}
[]{++global_x;}
[](int x,int y)->int {int z = x + y; return z + x;}
[] //沒有定義任何變量。使用未定義變量會引發錯誤
[x, &y] //x以傳值方式傳入,y以引用方式傳入。
[&] // 任何被使用到的外部變量都隱式地以引用方式加以引用。
[=] // 任何被使用到的外部變量都隱式地以傳值方式加以引用。
[&, x] // x顯式地以傳值方式加以引用。其余變量以引用方式加以引用。
[=, &z] // z顯示地以引用方式加以引用。其余變量以傳值方式加以引用。
C++隨機數產生
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int main()
{
int i,j; srand((unsigned)time(NULL));
for(i=0;i<10;i++){j = rand(); cout<<"隨機數:"<< j << endl;}
return 0;
}
可以采用setw(13)函數來進行格式化輸出。
C++引用:引用變量是一個別名,也就是說,它是某個已存在變量的另一個名字。一旦把引用初始化為某個變量,就可以使用該引用名稱或變量名稱來指向變量。
C++引用vs指針:主要有三個不同,一個是不存在空引用。引用必須連接到一塊合法的內存。二是一旦引用被初始化為一個對象,就不能被指向到另一個對象。指針可以在任何時候指向另一個對象。三是引用必須在創建時候被初始化。指針可以在任何時間被初始化。
typedef關鍵字:
typedef struct
{
char title[50];
char author[50];
char subject[100];
int book_id;
}Books;
typedef long int *pint32;
pint32 x, y, z;
C++面向對象
class Box
{
public:
double length;
double breadth;
double height;
};
Box Box1; Box Box2;
類的成員函數可以定義在類定義內部,或者單獨使用范圍解析運算符::來定義。在類定義中定義的成員函數把函數聲明為內聯的,即便沒有使用inline標識符。
#include <iostream>
using namespace std;
class Box
{
public:
double length;
double breadth;
double height;
double getVolume(void);
void setLength(double len);
void setBreadth(double bre);
void set Height(double hei);
};
double Box::getVolume(void){ return length * breadth * height;}
public: 公有成員在程序中類的外部是可訪問的。您可以不使用任何成員函數來設置和獲取公有變量的值。
private: 私有成員變量或函數在類的外部是不可訪問的,甚至是不可查看的。只有類和友元函數可以訪問私有成員。默認情況下,類的所有成員都是私有的。
protected: 保護成員變量或函數與私有成員十分相似,但有一點不同,保護成員在派生類中是可訪問的。
類的構造函數是類的一種特殊成員函數,它會在每次創建類的新對象時執行。構造函數的名稱與類的名稱完全相同,并且不會返回任何類型,也不會返回void。構造函數可用于為某些成員變量設置初始值。
#include <iostream>
using namespace std;
class Line
{
public:
void setLength(double len);
double getLength(void);
Line();
private:
double length;
}
Line::Line(void){cout<<"Object is being created"<< endl;}
類的析構函數是類的一種特殊的成員函數,它會在每次刪除所創建的對象時執行。析構函數的名稱與類的名稱是完全相同的,只是在前面加了個波浪號作為前綴,它不會返回任何值,也不能帶有任何參數。析構函數有助于在跳出程序前釋放資源。
拷貝構造函數是一種特殊的構造函數,它在創建對象時,是使用同一類中之前創建的對象來初始化新創建的對象。如果在類中沒有定義拷貝構造函數,編譯器會自行定義一個。。如果類帶有指針變量,并有動態內存分配,則它必須有一個拷貝構造函數。
#include <iostream>
using namespace std;
class Line
{
public:
int getLength(void); Line(int len); Line(const Line &obj); ~Line();
private:
int *ptr;
};
Line::Line(int len){cout<<"Normal constructor allocating ptr"<<endl;
ptr = new int; *ptr = len;}
Line::Line(const Line &obj)
{
cout<<"Copy constructor allocating ptr."<<endl;
ptr = new int; *ptr = *obj.ptr;
}
Line::~Line(void){cout<<"Freeing memory!"<<endl; delete ptr;}
類的友元函數是定義在類外部,但有權訪問類的所有私有成員和保護成員。盡管友元函數的原型有在類的定義中出現過,但是友元函數并不是成員函數。
友元可以是一個函數,該函數被稱為友元函數;友元也可以是一個類,該類被稱為友元類,在這種情況下,整個類及其所有成員都是友元。
class Box
{
double width;
public:
double length;
friend void printWidth(Box box);
void setWidth(double wid);
};
friend class ClassTwo;
內聯函數是通常與類一起使用。如果一個函數是內聯的,那么在編譯時,編譯器會把該函數的代碼副本放置在每個調用該函數的地方。
對內聯函數進行任何修改,都需要重新編譯函數的所有客戶端,因為編譯器需要重新更換一次所有代碼,否則將會繼續使用舊的函數。
如果想把一個函數定義為內聯函數,則需要在函數名前面放置關鍵字inline,在調用函數之前需要對函數進行定義。如果已定義的函數多于一行,編譯器會忽略inline限定符。
在類定義中的定義的函數都是內聯函數,即使沒有使用inline說明符。
在C++中,每一個對象都能通過this指針來訪問自己的地址。this指針是所有成員函數的隱含參數。因此,在成員函數內部,它可以用來指向調用對象。友元函數沒有this指針,因為友元不是類的成員。只有成員函數才有this指針。
一個指向C++類的指針與指向結構的指針類似,訪問指向類的指針的成員,需要使用成員訪問運算符->,就像訪問指向結構的指針一樣。與所有的指針一樣,您必須在使用指針之前,對指針進行初始化。
我們可以使用static關鍵字來把類成員定義為靜態的。當我們聲明類的成員為靜態時,這意味著無論創建多少個類的對象,靜態成員都只有一個副本。靜態成員在類的所有對象中是共享的。如果不存在其他的初始化語句,在創建第一個對象時,所有的靜態數據都會被初始化為0,我們不能把靜態成員放置在類的定義中,但是可以在類的外部通過使用范圍解析符::來重新聲明靜態變量從而對它進行初始化。
#include <iostream>
using namespace std;
class Box
{
public:
static int objectCount;
Box(double l=2.0, double b=2.0, double h=2.0)
{cout<<"Constructor called."<<endl; length=1; breadth=b; height = h;
objectCount++;}
double Volume(){return length*breadth*height;}
private:
double length; double breadth; double height;
};
int Box::objectCount = 0;
如果把函數成員聲明為靜態的,就可以把函數與類的任何特定對象獨立開來。靜態成員函數即使在類對象不存在的情況下也能被調用,靜態函數只要使用類名加范圍解析運算符::就可以訪問。
靜態成員函數只能訪問靜態數據成員,不能訪問其他靜態成員函數和類外部的其他函數。
靜態成員函數有一個類范圍,他們不能訪問類的this指針。您可以使用靜態成員函數來判斷類的某些對象是否已經被創建。
class Rectangle: public Shape
{
public:
int getArea(){return (width*height);}
}
派生類可以訪問基類中所有的非私有成員。因此基類成員如果不想被派生類的成員函數訪問,則應在基類中聲明為private。
一個派生類繼承了所有的基類方法,除了基類的構造函數、析構函數和拷貝構造函數、基類的重載運算符、基類的友元函數。
公有繼承:當一個類派生自公有基類時,基類的公有成員也是派生類的公有成員,基類的保護成員也是派生類的保護成員,基類的私有成員不能直接被派生類訪問,但是可以通過調用基類的公有和保護成員來訪問。
保護繼承:當一個類派生自保護基類時,基類的公有和保護成員將成為派生類的保護成員。
私有繼承:當一個類派生自私有基類時,基類的公有和保護成員將成為派生類的私有成員。
多繼承:一個子類可以有多個父類,它繼承了多個父類的特性。
class <派生類名>: <繼承方式1><基類名1>,<繼承方式2><基類名2>,...
C++允許在同一作用域中的某個函數和運算符指定多個定義,分別稱為函數重載和運算符重載。重載聲明是指一個與之前已經在該作用域內聲明過的函數或方法具有相同名稱的聲明,但是它們的參數列表和定義不相同。
當調用一個重載函數或重載運算符時,編譯器通過把所使用的參數類型與定義中的參數類型進行比較,決定選用最適合的定義。
重載的運算符是帶有特殊名稱的函數,函數名是由關鍵字operator和其后要重載的運算符符號構成的。與其他函數一樣,重載運算符有一個返回類型和一個參數列表。
Box operator+(const Box&);
聲明加法運算符用于把兩個Box對象相加,返回最終的Box對象。大多數的重載運算符可被定義為普通的非成員函數或者被定義為類成員函數。如果我們定義上面的函數為類的非成員函數,那么我們需要為每次操作傳遞兩個參數。如Box operator+(const Box&, const Box&);
C++多態意味著調用成員函數時,會根據調用函數的對象的類型來執行不同的函數。
#include <iostream>
using namespace std;
class Shape{
protected:
int width,height;
public:
Shape(int a=0, int b=0){width=a; height=b;}
int area(){cout<<"Parent class area:"<<endl; return 0;}
};
class Rectangle: public Shape{
public:
Rectangle(int a=0, int b=0):Shape(a,b){}
int area(){cout<<"Rectangle class area:"<<endl; return (width*height);}
};
class Triangle: public Shape{
public:
Triangle(int a=0, int b=0): Shape(a, b){}
int area(){cout<<"Triangle class area:"<<endl; return (width*height/2);}
};
int main()
{
Shape *shape; Rectangle rec(10,7); Triangle tri(10,5);
shape = &rec;
shape->area();
shape = &tri; shape->area(); return 0;
}
上述代碼導致錯誤輸出的原因是,調用函數area()被編譯器設置為基類中的版本,這就是所謂的靜態多態,或靜態鏈接-函數調用在程序執行前就準備好了。有時候這也被稱為早綁定,因為area()函數在程序編譯期間就已經設置好了。
class Shape{
protected:
int width, height;
public:
Shape(int a=0, int b=0){width = a; height = b;}
virtual int area(){cout<<"Parent class area:"<<endl; return 0;}
};
此時編譯器看的是指針的內容,而不是它的類型。因此,由于tri和rec類的對象的地址存儲在*shape中,所以會調用各自的area()函數。
每個子類都有一個函數area()的獨立實現。這就是多態的一般使用方式。有了多態,就可以有多個不同的子類,都帶有同一個名稱但是具有不同實現的函數,函數的參數甚至可以是相同的。
虛函數是在基類中使用關鍵字virtual聲明的函數。在派生類中重新定義基類中定義的虛函數時,會告訴編譯器不要靜態鏈接到該函數。
我們想要的是在程序中任意點可以根據所調用的對象類型來選擇調用的函數,這種操作被稱為動態鏈接,或后期綁定。
純虛函數:如果想要在基類中定義虛函數,以便在派生類中重新定義該函數更好地適用于對象,但是在基類中又不能對虛函數給出有意義的實現,這個時候就會使用虛函數。
class Shape{
protected:
int width, height;
public:
Shape(int a=0, int b=0){width=a; height=b;}
virtual int area() = 0;
};
C++數據抽象是指只向外界提供關鍵信息,并隱藏其后臺的實現細節,只表現必要的信息而不呈現細節。數據抽象是一種依賴于接口和實現分離的編程技術。
在C++中,我們使用訪問標簽來定義類的抽象接口。一個類可以包含零個或多個訪問標簽:a.使用公共標簽定義的成員都可以訪問該程序的所有部分。一個類型的抽象數據視圖是由它的公共成員來定義的。b.使用私有標簽定義的成員無法訪問到使用類的代碼。私有部分對使用類型的代碼隱藏了實現細節。
訪問標簽出現的頻率沒有限制。每個訪問標簽指定了緊隨其后的成員定義的訪問級別。指定的訪問級別會一直有效,直到遇到下一個訪問標簽或者遇到類主體的關閉右括號為止。
數據封裝是一種把數據和操作數據的函數捆綁在一起的概念,這樣能避免受到外界的干擾和誤用,數據抽象是一種僅向用戶暴露接口而把具體的實現細節隱藏起來的機制。
C++接口(抽象類):接口描述了類的行為和功能,而不需要完成類的特定實現。C++接口是使用抽象類來實現的,抽象類與數據抽象互不混淆,數據抽象是一個把實現細節與相關的數據分離開的概念。
如果類中至少有一個函數被聲明為純虛函數,則這個類就是抽象類。純虛函數是通過在聲明中使用"=0"來指定的。
class Box
{
public:
virtual double getVolume()=0;
private:
double length; double breadth; double height;
};
設計抽象類(ABC)的目的,是為了給其他類提供一個可以繼承的適當的基類。抽象類不能被用于實例化對象,它只能作為接口使用。如果試圖實例化一個抽象類的對象,會導致編譯錯誤。
因此,如果一個ABC的子類需要被實例化,則必須實現每個虛函數,這也意味著C++支持使用ABC聲明接口。如果沒有在派生類中重載純虛函數,就嘗試實例化該類的對象,會導致編譯錯誤。
可用于實例化對象的類被稱為具體類。
#include <iostream>
using namespace std;
class Shape
{
public:
virtual int getArea()=0;
void setWidth(int w){width = w;}
void setHeight(int h){height = h;}
protected:
int width; int height;
};
C++高級教程
回顧iostream標準庫,它提供了cin和cout方法分別用于從標準輸入讀取流和向標準輸出寫入流。
C++的另一個標準庫fstream則用于從文件讀取流和向文件寫入流。主要定義了三個新的數據類型:
ofstream 該數據類型表示輸出文件流,用于創建文件并向文件寫入信息
ifstream 該數據類型表示輸入文件流,用于從文件讀取信息
fstream 該數據類型通常表示文件流,且同時具有ofstream和ifstream兩種功能,這意味著它可以創建文件,向文件寫入信息,從文件讀取信息。
open函數是fstream、ifstream和ofstream對象的一個成員。
void open(const char *filename, ios::openmode mode);
ios::app 追加模式。所有寫入都追加到文件末尾
ios::ate 文件打開后定位到文件末尾
ios::in 打開文件用于讀取
ios::out 打開文件用于寫入
ios::trunc 如果該文件已經存在,其內容將在打開文件之前被截斷,即把文件長度設置為0.
可以把兩種或兩種以上的模式結合使用。
ofstream outfile;
outfile.open("file.dat", ios::out|ios::trunc);
fstream afile;
afile.open("file.dat", ios::out|ios::in);
當C++程序終止時,它會自動關閉刷新所有流,釋放所有分配的內存,并關閉所有打開的文件。
下面是close()函數的標準語法,close()函數是fstream、ifstream和ofstream對象的一個成員。
void close();
在C++編程中,我們使用流插入運算符<<向文件寫入信息,就像使用該運算符輸出信息到屏幕上一樣。讀取文件時亦類似。
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char data[100];
ofstream outfile;
cout<<"Writing to the file"<<endl; cout<<"Enter your name:";
cin.getline(data,100);
outfile<<data<<endl; cout<<"Enter your age:";
cin >> data; cin.ignore(); outfile<<data<<endl; outfile.close();
}
istream和ostream都提供了用于重新定位文件位置指針的成員函數。這些成員函數包括關于istream的seekg和關于ostream的seekp。
seekg和seekp的參數通常是一個長整型。第二個參數可以用于指定查找方向。查找方向可以是ios::beg(默認的,從流的開頭開始定位),也可以是ios::cur(從流的當前位置開始定位),也可以是ios::end(從流的末尾開始定位)。
文件位置指針是一個整數值,指定了從文件的起始位置到指針所在位置的字節數。
// 定位到fileObject的第n個字節(假設是ios::beg)
fileObject.seekg(n);
// 把文件的讀指針從fileObject當前位置向后移n個字節
fileObject.seekg(n, ios::cur);
// 把文件的讀指針從fileObject末尾往回移n個字節
fileObject.seekg(n, ios::end);
// 定位到fileObject的末尾
fileObject.seekg(0,ios::end);
C++動態內存分為兩個部分:棧是在函數內部聲明的所有變量都將占用棧內存;堆是程序中未使用的內存,在程序運行時可用于動態分配內存。
double* pvalue = NULL; //初始化為null的指針
pvalue = new double; // 為變量請求內存
if(!(pvalue = new double)){cout<<"Error: out of memory."<<endl; exit(1);}
delete pvalue;
char* pvalue = NULL;
pvalue = new char[20]; delete [] pvalue;
int ROW = 2; int COL = 3;
double **pvalue = new double* [ROW];
for(int i=0;i<COL;i++){pvalue[i] = new double[COL];}
for(int i=0; i<COL; i++){delete [] pvalue[i];}
delete [] pvalue;
#include <iostream>
using namespace std;
namespace first_space{void func(){cout<<"Inside first_space"<<endl;}}
namespace second_space
{void func(){cout<<"Inside second_space"<<endl;}}
int main(){first_space::func(); second_space::func();}
using namespace first_space;
命名空間可以定義在幾個不同的部分中,因此命名空間是由幾個單獨定義的部分組成的。一個命名空間的各個組成部分可以分散在多個文件中。所以,如果命名空間中的某個組成部分需要請求定義在另一個文件中的名稱,則仍然需要聲明該名稱。
#include <iostream>
#include <string>
using namespace std;
template <typename T>
inline T const& Max(T const& a, T const& b){return a<b?b:a;}
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
using namespace std;
template <class T>
class Stack{
private:
vector<T> elems;
public:
void push(T const&); void pop(); T top() const;
bool empty() const{return elems.empty();}
};
template <class T>
void Stack<T>::push(T const& elem){elems.push_back(elem);}
template<class T>
void Stack<T>::pop()
{
if(elems.empty())
throw out_of_range("Stack<>::pop():empty stack");
elems.pop_back();
}
template <class T>
T Stack<T>::top() const
{
if(elems.empty()) throw out_of_range("Stack<>::top():empty stack");
return elems.back();
}
int main()
{
try{
stack<int> inStack;
Stack<string> stringStack;
intStack.push(7); cout<<intStack.top()<<endl;
stringStack.push("hello"); cout<<stringStack.top()<<std::endl;
stringStack.pop(); stringStack.pop();
}
catch(exception const& ex){
ceer<<"Exception:"<<ex.what()<<endl; return -1;}
}
#define PI 3.14159
#define MIN(a,b) ((a)<(b)?a:b)
#define CONCAT(x,y) x##y
#define MKSTR( x ) #x
// C++多線程
#include <pthread.h>
pthread_create(thread, attr, start_outine, arg)
//thread 指向線程標識符指針
//attr 一個不透明的屬性對象,可以被用來設置線程屬性。您可以指定線程屬性對象,也可以使用默認值NULL
//start_routine 線程運行函數起始地址,一旦線程被創建就會執行
//arg 運行函數的參數。它必須通過把引用作為指針強制轉換為void類型進行傳遞。如果沒有傳遞參數,則使用NULL。
// 創建線程成功時,函數返回0,若返回值不為0則說明創建線程失敗。
#include <pthread.h>
pthread_exit(status)
//該函數用于顯式地退出一個線程。通常情況下,pthread_exit()函數是在線程完成工作后無需繼續存在時被調用。
如果main()是在它所創建的線程之前結束,并通過pthread_exit()退出,那么其他線程將繼續執行。否則,它們將在main()結束時自動被終止。
#include <iostream>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
void* say_hello(void* args){cout<<"Hello Runoob!"<<endl;}
int main()
{
pthread_t tids[NUM_THREADS];
for(int i=0; i<NUM_THREADS; i++)
{
int ret = pthread_create(&tids[i], NULL, say_hello, NULL);
if(ret!=0){cout<<"pthread_create error: error_code="<<ret<<endl;}
}
pthread_exit(NULL);
}
// g++ test.cpp -lpthread -o test.o
#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
#define NUM_THREADS
void *PrintHello(void *threadid)
{
int tid = *((int*)threadid);
cout<<"Hello Runoob! 線程ID, "<<tid<<endl;
pthread_exit(NULL);
}
int main()
{
pthread_t threads[NUM_THREADS];
int indexes[NUM_THREADS];
int rc; int i;
for(i=0; i<NUM_THREADS; i++)
{
cout<<"main(): 創建線程,"<< i << endl;
indexes[i] = i;
rc = pthread_create(&threads[i], NULL, PrintHello, (void*)&(indexes[i]));
if(rc){cout<<"Error:無法創建線程,"<<rc<<endl; exit(-1);}
}
pthread_exit(NULL);
}
#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
struct thread_data{int thread_id; char *message;};
void *PrintHello(void *threadarg)
{
struct thread_data *my_data;
my_data = (struct thread_data *) threadarg;
cout<<"Thread ID:"<<my_data->thread_id;
cout<<"Message:"<<my_data->thread_id;
pthread_exit(NULL);
}
int main()
{
pthread_t threads[NUM_THREADS];
struct thread_data td[NUM_THREADS];
int rc; int i;
for(i=0;i<NUM_THREADS;i++){
cout<<"main():creating thread,"<<i<<endl;
td[i].thead_id = i;
td[i].message = "This is message";
rc = pthread_create(&threads[i],NULL,PrintHello,(void*)&td[i]);
if(rc){cout<<"Error:unable to create thread,"<<rc<<endl; exit(-1);}}
pthread_exit(NULL);
}
pthread_join(threadid, status)
pthread_detach(threadid)
pthread_join()子程序阻礙調用程序,直到指定的threadid線程終止為止。當創建一個線程時,它的某個屬性會定義它是否是可連接的或可分離的。只有創建時定義為可連接的線程才可以被連接。
如果線程創建時被定義為可分離的,則它永遠也不能被連接。
C++資源庫
C++ STL標準模版庫是一套功能強大的C++模版類,提供了通用的模版類和函數,這些模版類和函數可以實現多種流行和常用的算法和數據結構,如向量、鏈表、隊列、棧。
容器:容器是用來管理某一類對象的集合。C++提供了各種不同類型的容器,比如deque、list、vector、map等。
算法:算法作用于容器,它們提供了執行各種操作的方式,包括對容器內容執行初始化、排序、搜索和轉換等操作。
迭代器:迭代器用于遍歷對象集合的元素。這些集合可能是容器,也可能是容器的子集。
C++標準庫可以分為兩個部分:
標準函數庫:這個庫是由通用的、獨立的、不屬于任何類的函數組成的。函數庫繼承自C語言。
面向對象類庫:這個庫是類及其相關函數的集合。