C++的基礎也能夠理解爲C的基礎。這裏主要是複習下其中的相對簡單的基礎部分。html
C++ 是一種中級語言,它是由 Bjarne Stroustrup 於 1979 年在貝爾實驗室開始設計開發的。ios
C++ 進一步擴充和完善了 C 語言,是一種面向對象的程序設計語言。C++ 可運行於多種平臺上,如 Windows、MAC 操做系統以及 UNIX 的各類版本。c++
菜雞教程:https://www.runoob.com/cplusplus/cpp-tutorial.htmlexpress
發佈時間 | 文檔 | 通稱 | 備註 |
---|---|---|---|
2015 | ISO/IEC TS 19570:2015 | - | 用於並行計算的擴展 |
2015 | ISO/IEC TS 18822:2015 | - | 文件系統 |
2014 | ISO/IEC 14882:2014 | C++14 | 第四個C++標準 |
2011 | ISO/IEC TR 24733:2011 | - | 十進制浮點數擴展 |
2011 | ISO/IEC 14882:2011 | C++11 | 第三個C++標準 |
2010 | ISO/IEC TR 29124:2010 | - | 數學函數擴展 |
2007 | ISO/IEC TR 19768:2007 | C++TR1 | C++技術報告:庫擴展 |
2006 | ISO/IEC TR 18015:2006 | - | C++性能技術報告 |
2003 | ISO/IEC 14882:2003 | C++03 | 第二個C++標準 |
1998 | ISO/IEC 14882:1998 | C++98 | 第一個C++標準 |
g++ 有些系統默認是使用 C++98,咱們能夠指定使用 C++11 來編譯 main.cpp 文件:數組
g++ -g -Wall -std=c++11 main.cpp
選項 | 解釋 |
---|---|
-ansi | 只支持 ANSI 標準的 C 語法。這一選項將禁止 GNU C 的某些特點, 例如 asm 或 typeof 關鍵詞。 |
-c | 只編譯並生成目標文件。 |
-DMACRO | 以字符串"1"定義 MACRO 宏。 |
-DMACRO=DEFN | 以字符串"DEFN"定義 MACRO 宏。 |
-E | 只運行 C 預編譯器。 |
-g | 生成調試信息。GNU 調試器可利用該信息。 |
-IDIRECTORY | 指定額外的頭文件搜索路徑DIRECTORY。 |
-LDIRECTORY | 指定額外的函數庫搜索路徑DIRECTORY。 |
-lLIBRARY | 鏈接時搜索指定的函數庫LIBRARY。 |
-m486 | 針對 486 進行代碼優化。 |
-o | FILE 生成指定的輸出文件。用在生成可執行文件時。 |
-O0 | 不進行優化處理。 |
-O | 或 -O1 優化生成代碼。 |
-O2 | 進一步優化。 |
-O3 | 比 -O2 更進一步優化,包括 inline 函數。 |
-shared | 生成共享目標文件。一般用在創建共享庫時。 |
-static | 禁止使用共享鏈接。 |
-UMACRO | 取消對 MACRO 宏的定義。 |
-w | 不生成任何警告信息。 |
-Wall | 生成全部警告信息。 |
下表列出了 C++ 中的保留字。這些保留字不能做爲常量名、變量名或其餘標識符名稱。安全
asm | else | new | this |
auto | enum | operator | throw |
bool | explicit | private | true |
break | export | protected | try |
case | extern | public | typedef |
catch | false | register | typeid |
char | float | reinterpret_cast | typename |
class | for | return | union |
const | friend | short | unsigned |
const_cast | goto | signed | using |
continue | if | sizeof | virtual |
default | inline | static | void |
delete | int | static_cast | volatile |
do | long | struct | wchar_t |
double | mutable | switch | while |
dynamic_cast | namespace | template |
完整關鍵字介紹可查閱:C++ 的關鍵字(保留字)完整介紹併發
1. asm異步
asm (指令字符串):容許在 C++ 程序中嵌入彙編代碼。函數
#include "stdafx.h" #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { unsigned int a; char inputKey; cout<<"輸入一個整數:"<<endl; cin>>a; unsigned int *c = &a;
__asm { mov eax, c; //c中存儲的a的地址->eax mov eax, [eax]; //a的值->eax add eax,1; mov a,eax; }
cout<<a<<endl; cin>>inputKey; return 0; }
2. autopost
auto(自動,automatic)是存儲類型標識符,代表變量"自動"具備本地範圍,塊範圍的變量聲明(如for循環體內的變量聲明)默認爲auto存儲類型。
可能在使用cout這類自動判斷類型的表達時能夠考慮auto。
10. const_cast:
const_cast<type_id> (expression)
該運算符用來修改類型的 const 或 volatile 屬性。除了 const 或 volatile 修飾以外, type_id 和 expression 的類型是同樣的。常量指針被轉化成很是量指針,而且仍然指向原來的對象;常量引用被轉換成很是量引用,而且仍然指向原來的對象;常量對象被轉換成很是量對象。
16. dynamic_cast
dynamic_cast(動態轉換),容許在運行時刻進行類型轉換,從而使程序可以在一個類層次結構安全地轉換類型。dynamic_cast 提供了兩種轉換方式,把基類指針轉換成派生類指針,或者把指向基類的左值轉換成派生類的引用。
19. explicit
explicit(顯式的)的做用是"禁止單參數構造函數"被用於自動型別轉換,其中比較典型的例子就是容器類型。在這種類型的構造函數中你能夠將初始長度做爲參數傳遞給構造函數。
20. export
爲了訪問其餘編譯單元(如另外一代碼文件)中的變量或對象,對普通類型(包括基本數據類、結構和類),能夠利用關鍵字 extern,來使用這些變量或對象時;
可是對模板類型,則必須在定義這些模板類對象和模板函數時,使用標準 C++ 新增長的關鍵字 export(導出)。
21. extern
extern(外部的)聲明變量或函數爲外部連接,即該變量或函數名在其它文件中可見。被其修飾的變量(外部變量)是靜態分配空間的,即程序開始時分配,結束時釋放。用其聲明的變量或函數應該在別的文件或同一文件的其它地方定義(實現)。在文件內聲明一個變量或函數默認爲可被外部使用。在 C++ 中,還可用來指定使用另外一語言進行連接,這時須要與特定的轉換符一塊兒使用。目前僅支持 C 轉換標記,來支持 C 編譯器連接。使用這種狀況有兩種形式:
extern "C" 聲明語句
extern "C" { 聲明語句塊 }
31. mutable
mutable(易變的)是 C++ 中一個不經常使用的關鍵字。只能用於類的非靜態和很是量數據成員。因爲一個對象的狀態由該對象的非靜態數據成員決定,因此隨着數據成員的改變,對像的狀態也會隨之發生變化。若是一個類的成員函數被聲明爲 const 類型,表示該函數不會改變對象的狀態,也就是該函數不會修改類的非靜態數據成員。可是有些時候須要在該類函數中對類的數據成員進行賦值,這個時候就須要用到 mutable 關鍵字。
32. namespace
namespace(命名空間)用於在邏輯上組織類,是一種比類大的結構。
34. operator
operator(操做符)用於操做符重載。這是 C++ 中的一種特殊的函數。
38.register
register(寄存器)聲明的變量稱着寄存器變量,在可能的狀況下會直接存放在機器的寄存器中;但對 32 位編譯器不起做用,當 global optimizations(全局優化)開的時候,它會作出選擇是否放在本身的寄存器中;不過其它與 register 關鍵字有關的其它符號都對32位編譯器有效。
39. reinterpret_cast
用法:
reinpreter_cast<type-id> (expression)
type-id 必須是一個指針、引用、算術類型、函數指針或者成員指針。它能夠把一個指針轉換成一個整數,也能夠把一個整數轉換成一個指針(先把一個指針轉換成一個整數,在把該整數轉換成原類型的指針,還能夠獲得原先的指針值)。
45. static_cast
用法:
static_cast < type-id > ( expression )
該運算符把 expression 轉換爲 type-id 類型,但沒有運行時類型檢查來保證轉換的安全性。它主要有以下幾種用法:
注意 static_cast 不能轉換掉 expression 的 const、volitale、或者 __unaligned 屬性。
48. template
template(模板),C++ 中泛型機制的實現。
50. throw
throw(拋出)用於實現 C++ 的異常處理機制,能夠經過 throw 關鍵字"拋出"一個異常。
52. try
try(嘗試)用於實現 C++ 的異常處理機制。能夠在 try 中調用可能拋出異常的函數,而後在 try 後面的 catch 中捕獲並進行處理。
54. typeid
指出指針或引用指向的對象的實際派生類型。
55. typename
typename(類型名字)關鍵字告訴編譯器把一個特殊的名字解釋成一個類型。在下列狀況下必須對一個 name 使用 typename 關鍵字:
61. volatile
volatile(不穩定的)限定一個對象可被外部進程(操做系統、硬件或併發線程等)改變,聲明時的語法以下:
int volatile nVint;
這樣的聲明是不能達到最高效的,由於它們的值隨時會改變,系統在須要時會常常讀寫這個對象的值。所以經常使用於像中斷處理程序之類的異步進程進行內存單元訪問。
62. wchar_t
wchar_t 是寬字符類型,每一個 wchar_t 類型佔 2 個字節,16 位寬。漢字的表示就要用到 wchar_t。
"hello, dear" -------------------------- "hello, \ dear" -------------------------- "hello, " "d" "ear"
類型限定符提供了變量的額外信息。
限定符 | 含義 |
---|---|
const | const 類型的對象在程序執行期間不能被修改改變。 |
volatile | 修飾符 volatile 告訴編譯器不須要優化volatile聲明的變量,讓程序能夠直接從內存中讀取變量。對於通常的變量編譯器會對變量進行優化,將內存中的變量值放在寄存器中以加快讀寫效率。 |
restrict | 由 restrict 修飾的指針是惟一一種訪問它所指向的對象的方式。只有 C99 增長了新的類型限定符 restrict。 |
存儲類定義 C++ 程序中變量/函數的範圍(可見性)和生命週期。這些說明符放置在它們所修飾的類型以前。下面列出 C++ 程序中可用的存儲類:
從 C++ 11 開始,auto 關鍵字再也不是 C++ 存儲類說明符,且 register 關鍵字被棄用。
使用 thread_local 說明符聲明的變量僅可在它在其上建立的線程上訪問。 變量在建立線程時建立,並在銷燬線程時銷燬。 每一個線程都有其本身的變量副本。
疑惑:thread_local 說明符能夠與 static 或 extern 合併?
Ref: thread_local變量
C++中有4種存儲週期:
哪些變量能夠被聲明爲thread_local?
thread_local int x; //A thread-local variable at namespace scope 全局變量 class X { static thread_local std::string s; //A thread-local static class data member 靜態成員 }; static thread_local std::string X::s; //The definition of X::s is required 靜態成員 void foo() { thread_local std::vector<int> v; //A thread-local local variable 本地變量 }
Ref: thread_local變量
線程外的影響不了線程內的東西,線程內的能力仍是能影響到主線程share的thread_local的變量。
#include <thread> thread_local int g_n = 1; void f() { g_n++; printf("id=%d, n=%d\n", std::this_thread::get_id(),g_n); } void foo() { thread_local int i=0; printf("id=%d, n=%d\n", std::this_thread::get_id(), i); i++; } void f2() { foo(); foo(); } int main() { g_n++; f(); // 主線程這裏本身+1,以後又被t1,t2分別再+1,最後獲得3 std::thread t1(f); // 這裏的全局的g_n是線程本身的 std::thread t2(f); t1.join(); t2.join(); f2(); std::thread t4(f2); std::thread t5(f2); t4.join(); t5.join(); return 0; }
int my_array[5] = {1, 2, 3, 4, 5}; // 每一個數組元素乘於 2 for (int &x : my_array) { x *= 2; cout << x << endl; }
// auto 類型也是 C++11 新標準中的,用來自動獲取變量的類型 for (auto &x : my_array) { x *= 2; cout << x << endl; }
C++11 提供了對匿名函數的支持,稱爲 Lambda 函數(也叫 Lambda 表達式)。
Lambda 表達式把函數看做對象。Lambda 表達式能夠像對象同樣使用。
Ref: c++ Lambda函數學習
對於sort這樣的函數帶來了福音,例如:
#include <algorithm> #include <cmath> void abssort(float *x, unsigned N) { std::sort(x, x + N, [](float a, float b) { return std::abs(a) < std::abs(b); }); }
std::cout << [](float f) { return std::abs(f); } (-3.5); std::cout << [](float f) -> int { return std::abs(f); } (-3.5);
這個語句與前面的不一樣之處在於,lambda 表達式的返回時不是 float 而是 int。
第一個返回3.5;第二個返回3。
std::function<int()> lambda = [] () -> int { return val * 100; };
float f0 = 1.0; std::cout << [=](float f) { return f0 + std::abs(f); } (-3.5); 傳值:其輸出值是 4.5 --------------------------------------------------------------------------------- float f0 = 1.0; std::cout << [&](float f) { return f0 += std::abs(f); } (-3.5); std::cout << '\n' << f0 << '\n'; 傳引用:輸出值是 4.5 和 4.5 --------------------------------------------------------------------------------- float f0 = 1.0; std::cout << [=](float f) mutable { return f0 += std::abs(f); } (-3.5); std::cout << '\n' << f0 << '\n';
若是以傳值的形式捕獲外部變量,那麼,lambda 體不容許修改外部變量。 你會以爲輸出值是什麼呢?答案是,4.5 和 1.0。 --------------------------------------------------------------------------------- float f0 = 1.0f; float f1 = 10.0f; std::cout << [=, &f0](float a) { return f0 += f1 + std::abs(a); } (-3.5); std::cout << '\n' << f0 << '\n'; 混合機制:這個例子的輸出是 14.5 和 14.5。
小總結:
[] // 不捕獲任何外部變量 [=] // 以值的形式捕獲全部外部變量 [&] // 以引用形式捕獲全部外部變量 [x, &y] // x 以傳值形式捕獲,y 以引用形式捕獲 [=, &z] // z 以引用形式捕獲,其他變量以傳值形式捕獲 [&, x] // x 以值的形式捕獲,其他變量以引用形式捕獲
序號 | 函數 & 描述 |
---|---|
1 | double cos(double); 該函數返回弧度角(double 型)的餘弦。 |
2 | double sin(double); 該函數返回弧度角(double 型)的正弦。 |
3 | double tan(double); 該函數返回弧度角(double 型)的正切。 |
4 | double log(double); 該函數返回參數的天然對數。 |
5 | double pow(double, double); 假設第一個參數爲 x,第二個參數爲 y,則該函數返回 x 的 y 次方。 |
6 | double hypot(double, double); 該函數返回兩個參數的平方總和的平方根,也就是說,參數爲一個直角三角形的兩個直角邊,函數會返回斜邊的長度。 |
7 | double sqrt(double); 該函數返回參數的平方根。 |
8 | int abs(int); 該函數返回整數的絕對值。 |
9 | double fabs(double); 該函數返回任意一個浮點數的絕對值。 |
10 | double floor(double); 該函數返回一個小於或等於傳入參數的最大整數。 |
#include <iostream> #include <ctime> #include <cstdlib> using namespace std; int main () { int i,j; // 設置種子 srand( (unsigned)time(NULL) ); /* 生成 10 個隨機數 */ for( i = 0; i < 10; i++ ) { // 生成實際的隨機數 j= rand(); cout <<"隨機數: " << j << endl; } return 0; }
參數中的數組有size,好處就是」能夠重載";平時仍是最好加個size的參數。
數組的缺陷 (1):
arr[5]做爲參數的話,sizeof(arr)指的是其中一個元素的大小,不是整個數組的。
double getAverage(int *arr, int size); //形式參數是一個指針: double getAverage(int arr[5]); // 重載函數,形式參數是一個已定義大小的數組: double getAverage2(int arr[]); // 不可重載,形式參數是一個未定義大小的數組:
數組的缺陷 (2):
C++中函數是不能直接返回一個數組的,可是數組其實就是指針,因此可讓函數返回指針來實現。
C++ 中有大量的函數用來操做以 null 結尾的字符串:
序號 | 函數 & 目的 |
---|---|
1 | strcpy(s1, s2); 複製字符串 s2 到字符串 s1。 |
2 | strcat(s1, s2); 鏈接字符串 s2 到字符串 s1 的末尾。 |
3 | strlen(s1); 返回字符串 s1 的長度。 |
4 | strcmp(s1, s2); 若是 s1 和 s2 是相同的,則返回 0;若是 s1<s2 則返回值小於 0;若是 s1>s2 則返回值大於 0。 |
5 | strchr(s1, ch); 返回一個指針,指向字符串 s1 中字符 ch 的第一次出現的位置。 |
6 | strstr(s1, s2); 返回一個指針,指向字符串 s1 中字符串 s2 的第一次出現的位置。 |
把引用做爲返回值
double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0}; double& setValues( int i ) { return vals[i]; // 返回第 i 個元素的引用 } // 函數能夠放在左邊 setValues(1) = 20.23; // 改變第 2 個元素 setValues(3) = 70.8; // 改變第 4 個元素
注意:返回一個對局部變量的引用是不合法的,可是,能夠返回一個對靜態變量的引用
Ref: 【C++】爲何不能定義數組的引用,卻可定義變量的引用
數組的引用的能夠定義的,好比:
int a[10]; int(&ra)[10]=a; // 這個纔是正牌的 數組的引用,用sizeof(ra)能夠看出來
或者:
// 數組是個地址,那麼先定義一個int地址的引用int*& ,數組名有const特性,因此引用也要是個const
int* const& ra=a;
// 不能定義引用數組,就是全部元素都是引用的數組 int& ra[10]; //這個是不行的 ,定義數組時要分配空間,而引用是不佔用內存空間的,因此c++規定不能夠定義引用數組
引用指代數組的一個例子:
bool array_assign(int (&p)[3],int (&q)[3])
{ //std::cout<<sizeof(p)<<std::endl; if(sizeof(p)!=sizeof(q))
{ std::cout<<"The subscript values do not match@!!!"<<std::endl; return false; } for(size_t i=0;i<sizeof(q)/sizeof(q[0]);i++){ p[i]=q[i]; } return true; } int main() { int a[3]={2,8,16}; int b[3]; bool rest; rest=array_assign(b,a); if(rest)
{ for(size_t i=0;i<3;i++)
{ std::cout<<b[i]<<std::endl; } } }
[?] 引用與指針有何區別?什麼時候只能使用指針不能使用引用?
1.若是一個指針所指向的對象,須要用分支語句加以肯定,或者在中途須要改變他所指的對象,那麼在它初始化以後須要爲他賦值,而引用只能在初始化時指定被引用的對象,因此不能勝任。【過程當中須要改變所指時】
2.有時一個指針的值多是空指針,例如當把指針做爲函數的參數類型或返回類型是,有時會用空指針表達特定的含義,而沒用空引用之說。【空指針】
3.使用函數指針,因爲沒有函數引用,因此函數指針沒法被引用替代。【函數指針】
4.使用new建立的對象或數組,須要用指針來存儲它的地址。【本就是存地址】
5.以數組形式傳遞大批量數據時,須要用指針類型接受參數。【數組的救星】
Goto 菜雞教程:https://www.runoob.com/cplusplus/cpp-date-time.html
#include <iostream> #include <ctime> using namespace std; int main( ) { // 基於當前系統的當前日期/時間 time_t now = time(0); cout << "1970 到目前通過秒數:" << now << endl; tm *ltm = localtime(&now); // 輸出 tm 結構的各個組成部分 cout << "年: "<< 1900 + ltm->tm_year << endl; cout << "月: "<< 1 + ltm->tm_mon<< endl; cout << "日: "<< ltm->tm_mday << endl; cout << "時間: "<< ltm->tm_hour << ":"; cout << ltm->tm_min << ":"; cout << ltm->tm_sec << endl; }
頭文件 | 函數和描述 |
---|---|
<iostream> | 該文件定義了 cin、cout、cerr 和 clog 對象,分別對應於標準輸入流、標準輸出流、非緩衝標準錯誤流和緩衝標準錯誤流。 |
<iomanip> | 該文件經過所謂的參數化的流操縱器(好比 setw 和 setprecision),來聲明對執行標準化 I/O 有用的服務。 |
<fstream> | 該文件爲用戶控制的文件處理聲明服務。咱們將在文件和流的相關章節討論它的細節。 |
預約義的對象 cout 是 iostream 類的一個實例。cout 對象"鏈接"到標準輸出設備,一般是顯示屏。cout 是與流插入運算符 << 結合使用的
預約義的對象 cin 是 iostream 類的一個實例。cin 對象附屬到標準輸入設備,一般是鍵盤。cin 是與流提取運算符 >> 結合使用的
預約義的對象 cerr 是 iostream 類的一個實例。cerr 對象附屬到標準錯誤設備,一般也是顯示屏,可是 cerr 對象是非緩衝的,且每一個流插入到 cerr 都會當即輸出。
預約義的對象 clog 是 iostream 類的一個實例。clog 對象附屬到標準錯誤設備,一般也是顯示屏,可是 clog 對象是緩衝的。這意味着每一個流插入到 clog 都會先存儲在緩衝在,直到緩衝填滿或者緩衝區刷新時纔會輸出。
舉個栗子:一個簡單的權限控制打印,用於程序調試。
/*****************************************************************************/ // ::print priority #define USER_EMERG "0" /* system is unusable */ #define USER_ALERT "1" /* action must be taken immediately */ #define USER_CRIT "2" /* critical conditions */ #define USER_ERR "3" /* error conditions */ #define USER_WARNING "4" /* warning conditions */ #define USER_NOTICE "5" /* normal but significant condition */ #define USER_INFO "6" /* informational */ #define USER_DEBUG "7" /* debug-level messages */ #define USER_DEFAULT USER_NOTICE /* the default kernel loglevel */ // ::print controller #ifdef ENABLE_DSDEBUG #define ENABLE_DSINFO #define dcout std::cout #else #define dcout 0 && std::cout #endif #ifdef ENABLE_DSINFO #define ENABLE_DSDEFAULT #define icout std::cout #else #define icout 0 && std::cout #endif #ifdef ENABLE_DSDEFAULT #define ncout std::cout #define wcout std::cout #define ecout std::cout #define ccout std::cout #define acout std::cout #define ecout std::cout #else #define ncout 0 && std::cout #define wcout 0 && std::cout #define ecout 0 && std::cout #define ccout 0 && std::cout #define acout 0 && std::cout #define ecout 0 && std::cout #endif
Ref: https://www.runoob.com/cplusplus/cpp-files-streams.html
要在 C++ 中進行文件處理,必須在 C++ 源代碼文件中包含頭文件 <iostream> 和 <fstream>。
數據類型 | 描述 |
---|---|
ofstream | 該數據類型表示輸出文件流,用於建立文件並向文件寫入信息。 |
ifstream | 該數據類型表示輸入文件流,用於從文件讀取信息。 |
fstream | 該數據類型一般表示文件流,且同時具備 ofstream 和 ifstream 兩種功能,這意味着它能夠建立文件,向文件寫入信息,從文件讀取信息。 |
struct Point { int x; int y; int z; }; Point p = {1, 2, 3};
// 該函數以結構指針做爲參數 void printBook( struct Books *book ) { cout << "書標題 : " << book->title <<endl; cout << "書做者 : " << book->author <<endl; cout << "書類目 : " << book->subject <<endl; cout << "書 ID : " << book->book_id <<endl; } Books Book1; // 定義結構體類型 Books 的變量 Book1 printBook( &Book1 );
typedef struct Books { char title[50]; char author[50]; char subject[100]; int book_id; }Books;
End.