本文來自菜鳥教程的C語言教程和C++教程的學習筆記,對其中的示例有所刪減與變更,建議以以下兩個鏈接為準。雖說C++是C的擴展,但貌似二者存在差集,而本文只展示了兼容部分。
C 語言教程 | 菜鳥教程 (runoob.com)https://www.runoob.com/cprogramming/c-tutorial.htmlC++ 教程 | 菜鳥教程 (runoob.com)https://www.runoob.com/cplusplus/cpp-tutorial.html
1、C語言的演化歷程
可表示為:01-》匯編-》C語言
(1)硬件電路只能表示0、1兩個狀態(tài),因此最開始編程時,使用的是0101010110101...進行表示,當要做加法時,可以用特定序列(如010101來標識),而對于不同的硬件電路,會有不同的表示方法,因此需要根據(jù)硬件電路來定義,并在編程時查表。
(2)當表示加法的硬件電路統(tǒng)一標準后,那么特定序列就會固定下來,這時候人們使用ADD這樣的標志來表示特定序列,即使用指令方式來表示,這樣就形成了很多指令集,形成匯編語言。
(3)基于匯編語言,發(fā)明了C語言,避免了查詢指令來進行編程,極大提高了編程效率,這就涉及到編譯器的出現(xiàn),但不同廠家編譯器不兼容,會導致同樣的代碼編譯不成功。為了解決這個問題,規(guī)定了C標準,如C11。但即使這樣,各個廠商為了自身利益,還是產(chǎn)生了很多編譯器。
2、C常用編譯器
最常用的免費可用的編譯器是GNU工具的gcc編譯器:在Linux為gcc指令,在Windows 上需要安裝 MinGW。這也是搭建環(huán)境時需要安裝的,不過一般使用IDE,如VS2019集成環(huán)境。
3、程序結構
#include <stdio.h> // 預處理器指令,提供接口調用,告訴編譯器在編譯前要包含該文件 // 主函數(shù),每個C程序都必須有一個主函數(shù)作為入口,程序運行的起點 int main() // main為函數(shù)名,int表示該函數(shù)返回int類型,int為整形 { /* 注釋的方式有2種,編譯器將忽略注釋內容 */ printf('Hello, World! \n'); // printf為stdio.h的接口,包含后才能使用 return 0; // 終止主函數(shù),返回0,因此當你看到0時,說明程序已經(jīng)終止運行了 }
4、基本語法
從“3、程序結構”中,我們知道語句結束時,需要使用語句結束符“;”;注釋時有2種方式,注釋一行“\\”和注釋多行“\*\*”;函數(shù)或變量會使用函數(shù)名來標識,被稱為標識符,如main,當然標識符是有規(guī)則的;我們還使用了關鍵字return、int等,他們表示某種特定的功能,因此不能作為標志符來使用;在這個程序中,還有空格的使用,空格分隔語句的各個部分,讓編譯器能識別語句中的某個元素(比如 int)在哪里結束,下一個元素在哪里開始。
這些有規(guī)律的組成就是基本語法,相當于人們說話時的語言組成。因此,每個編寫程序的人,口才都應該很好才行,至少要善于組織語言。
類型分類 | 類型關鍵字 | 存儲大?。ㄗ止?jié))/用途 | 值范圍(亦即存儲大小,因系統(tǒng)類型、系統(tǒng)位數(shù)而異)/描述 | ||
算數(shù)類型 | 基本類型 | 整數(shù)類型 | char | 1 | -1~127或0~255 |
unsigned char | 1 | 0~255 | |||
signed char | 1 | -128~127 | |||
int | 2或4 | -32,768~32,767或-2147483648~2147483647 | |||
unsigned int | 2或4 | 0~65535或0~4294967295 | |||
short | 2 | -32768~32767 | |||
unsigned short | 2 | 0~65,535 | |||
long | 4 | -2147483648~2147483647 | |||
unsigned long | 4 | 0~4294967295 | |||
浮點類型 | float | 4 | 1.2E-38~3.4E+38(精度:6位有效位) | ||
double | 8 | 2.3E-308~1.7E+308(精度:15位有效位) | |||
long double | 16 | 3.4E-4932~1.1E+4932(精度:19位有效位) | |||
枚舉類型 | |||||
void類型 | void | 函數(shù)返回為空 | 聲明函數(shù)返回為空值,如void test(); | ||
函數(shù)參數(shù)為空 | 不傳入?yún)?shù)時,可表示為int test(void); | ||||
指針指向 void | 可指向任何類型的數(shù)據(jù),如void *test( size_t size ); | ||||
派生類型 | 指針類型 | ||||
數(shù)組類型 | |||||
結構類型 | |||||
共用體類型 | |||||
函數(shù)類型 |
從“二、數(shù)據(jù)類型”的表格中,我們可以通過關鍵字定義其變量類型,如char c,表示一個字節(jié)(八位)的整數(shù)類型。特別的,void表示類型的缺失。除此之外,C 語言也允許定義各種其他類型的變量,比如枚舉、指針、數(shù)組、結構、共用體等等。
變量是一個存儲名稱,用于告訴編譯器在何處創(chuàng)建變量的存儲,定義與聲明的方式如下表:
變量定義 | 變量聲明 | 區(qū)別 | |
語法結構 | type variable;//可以是list type variable_name = value;//可以是list | 在變量的基礎上增加關鍵字extern,表示該變量若在別的文件中定義了,則為引入 | 變量定義的同時也意味著聲明,并建立了存儲空間,而聲明不需要創(chuàng)建存儲空間,因為在其他文件(或函數(shù)外部)的這個變量已經(jīng)創(chuàng)建,為外部變量(全局變量),當extern int a=1;則等價于int a=1 |
隱式初始化 | int a; int a,b; | extern int a; extern int a,b; | |
顯示初始化 | int a=1; int a=1,b=2; | extern int a=1; extern int a=1,b=2; |
變量類型與注意事項如下表所示:
描述 | |
局部變量 | 不會自動初始化,需要賦值使用 |
全局變量 | 自動初始化,不同類型初始化如下: int -》 0 char -》 '\0' float -》 0 double -》 0 pointer -》 NULL |
形式變量 | 函數(shù)形式參數(shù),作用于函數(shù)本身,優(yōu)先級高于全局變量、局部變量 |
從“二、數(shù)據(jù)類型”的表格中,我們了解到了基本數(shù)據(jù)類型。而常量可以是任何的基本數(shù)據(jù)類型,比如整數(shù)常量、浮點常量、字符常量,或字符串字面值,也有枚舉常量。
定義常量有2種方式,而常量名稱通常為大寫,如下表:
定義方式 | 舉例 | 備注 |
使用 #define 預處理器 | #define LENGTH 10; | |
使用 const 關鍵字 | const int LENGTH = 10; | |
使用 typedef 關鍵字 | typedef unsigned char BYTE; | typedef 僅限于為類型定義符號名稱,嚴格意義上算不上常量 |
字符常量如下表:
轉義序列 | 含義 |
\\ | \ 字符 |
\' | ' 字符 |
\' | ' 字符 |
\? | ? 字符 |
\a | 警報鈴聲 |
\b | 退格鍵 |
\f | 換頁符 |
\n | 換行符 |
\r | 回車 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ooo | 一到三位的八進制數(shù) |
\xhh . . . | 一個或多個數(shù)字的十六進制數(shù) |
存儲類定義 C 程序中變量/函數(shù)的范圍(可見性)和生命周期。這些說明符放置在它們所修飾的類型之前,作用周期與生命周期如下表:
存儲類 | 定義方法 | 作用域 | 生命周期 |
auto | auto int a; | 局部 | 調用一次函數(shù)(若在函數(shù)中定義)后,則自動釋放 |
register | register int a; | 寄存器 | 取決于硬件和實現(xiàn)的限制 |
static | static int a; | 局部 | 值初始化一次,調用一次函數(shù)(若在函數(shù)中定義)后,不會自動釋放相當于擁有全局壽命 |
extern | extern int count; | 全局 | extern 是用來在另一個文件中聲明一個全局變量或函數(shù),擁有全局壽命(程序一直運行,則一直存在) |
運算符是一種告訴編譯器執(zhí)行特定的數(shù)學或邏輯操作的符號,如下表所示:
名稱/運算符 | 注意事項 | |
算數(shù)運算符 | 加 + | |
減 - | ||
乘 * | ||
除 / | 得到整數(shù)部分 | |
取余 % | ||
自增 ++ | 放在變量前,先自增1 放在變量后,后自增1 | |
自減 -- | 放在變量前,先自減1 放在變量后,后自減1 | |
關系運算符 | 恒等于 == | |
不等于 != | ||
大于 > | ||
小于 < | ||
大于等于 >= | ||
小于等于 <= | ||
邏輯運算符 | 與 && | |
或 || | ||
非 ! | ||
位運算符 | 與 & | 二進制運算 |
或 | | 二進制運算 | |
異 ^ | 二進制運算,兩個值不一樣則為真 | |
取反 ~ | 二進制運算 | |
賦值運算符 | 等于 = | |
相加并等于 += | ||
相減并等于 -= | ||
相乘并等于 *= | ||
相除并等于 /= | ||
取余并等于 %= | ||
左移并等于 <<= | 二進制運算 | |
右移并等于 >>= | 二進制運算 | |
與并等于 &= | 二進制運算 | |
或并等于 |= | 二進制運算 | |
異并等于 ^= | 二進制運算 | |
雜項運算符 | 獲取變量存儲大小 sizeof() | |
獲取變量地址 & | ||
指向一個變量 * | 定義指針(int* ptr;)/指針取值(*ptr;) | |
條件表達式 ?: | (如果條件為真)?(則值為 X):(否則值為 Y) |
滿足條件則執(zhí)行A語句,不滿足則執(zhí)行B語句,這就是判斷的作用,如下表所示:
樣式1 | 樣式2 | 備注 | |
if | if(判斷條件) {...} | if(判斷條件) {...} else {...} | if可嵌套 |
switch | switch(變量) { case 值: ... break; } | switch(變量) { case 值: ... break; default: ... } | switch可嵌套 case可多個 |
? : | (如果條件為真)?(則值為 X):(否則值為 Y) |
不斷地有規(guī)律地執(zhí)行同一代碼塊,避免不斷地寫重復代碼,這就是循環(huán)的作用之一,如下表所示:
樣式一 | 樣式二 | 備注 | |
while | while(判斷條件) {...} | do{...}while(判斷條件); | 樣式二至少能執(zhí)行一次 |
for | for ( init a=1; a<5; a++ ) {...} | 三個表達式,任意一個表達式均可省略 | for(;;)等價于while(1) |
循環(huán)控制語句如下表:
控制語句 | 描述 |
break 語句 | 終止 loop 或 switch 語句,程序流將繼續(xù)執(zhí)行緊接著 loop 或 switch 的下一條語句。 |
continue 語句 | 引起循環(huán)跳過主體的剩余部分,立即重新開始測試條件。 |
goto 語句 | 將控制轉移到被標記的語句。但是不建議在程序中使用 goto 語句。 |
函數(shù)就是特定功能的代碼塊,有著特定的輸入輸出,可理解為接口,如下表所示:
樣式一 | 備注 | |
定義函數(shù) | (返回類型) 函數(shù)名(參數(shù)列表) {...} | 函數(shù)的參數(shù)可以是 實際值(傳值調用) 指針(引用調用) 函數(shù)(回調) |
函數(shù)聲明 | (返回類型) 函數(shù)名(參數(shù)列表); | |
調用函數(shù) | 函數(shù)名(參數(shù)列表); |
數(shù)組用于存儲一個固定大小的相同類型元素的順序集合,如下表所示:
樣式 | 備注 | |
聲明數(shù)組 | (類型) 數(shù)組名[ 整數(shù)值 ]; | |
初始化數(shù)組 | double balance[5] = {1.0, 2.0, 3.0, 4.0, 5.0}; | 整數(shù)值可省略,賦值后,默認整數(shù)值為賦值元素數(shù)量 |
訪問數(shù)組元素 | 數(shù)組名[下標]; | |
多維數(shù)組 | int threedim[5][10][4]; | |
傳遞數(shù)組給函數(shù) | void myFunction(int *param){}; void myFunction(int param[10]){}; | 直接傳數(shù)組或傳指針 |
從函數(shù)中返回數(shù)組 | static int r[10]; return r; | 直接返回數(shù)組 |
枚舉用于多個同類型數(shù)據(jù)一起賦值,如下表所示:
方式一 | 方式二 | 方式三 | |
定義枚舉變量 | enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN }; enum DAY day; | enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } day; | enum { MON=1, TUE, WED, THU, FRI, SAT, SUN } day; |
轉換枚舉變量 | int a=1; enum day weekend; weekend = ( enum day ) a; |
指針用于對內存操作,如下表所示:
形式一 | 形式二 | |
聲明指針 | (類型) *(指針名); | (類型)* (指針名); |
指針賦值 | 指針名=&變量名 | |
變量訪問 | *指針名 | |
變量賦值 | *指針名=值 | |
常用初始化 | int *ptr = NULL; //ptr 的地址是 0x0 |
指針有許多作用,如下表所示:
形式一 | 形式二 | 備注 | |
指針運算 | 支持運算符 ++、--、+、- 關系運算 ==、<、> ... 運算時,根據(jù)數(shù)據(jù)類型不同,以該類型所占用字節(jié)作為一個單位運算 | ||
指針數(shù)組 | int var[3] = {1, 2, 3}; int *ptr[3]; ptr[1] = &var[1]; *ptr[1]; // 訪問變量 | const char *names[] = { 'name1', 'name2', }; names[1]; // 訪問變量 | *names[]直接賦值,因此指針取值使用names[1],而ptr[1]本身取得是變量地址,因此使用常規(guī)取值方式即可。 |
多重指針 | int *Pt1; int **Pt1; int ***Pt1; ... | ||
指針形參 | void def_name(int *par) { *par = 666; } int a; def_name( &a ); printf(a); | int def_name(int *arr) { int sum = 0; for (i = 0; i < size; ++i) { sum += arr[i]; } } int balance[5] = {1000, 2, 3, 17, 50}; def_name(balance) | 可傳內存地址、可傳數(shù)組 |
返回指針 | int * def_name() {...} | int * getRandom( ) { static int arr[2]={1,2}; return arr; } | |
函數(shù)指針 | int def_name(int a) { ... } int a=1; int (* p)(int) = &def_name; // &可以省略 p(a); | ||
結構指針 | struct Books { char title[50]; char author[50]; char subject[100]; int book_id; }; struct Books *struct_pointer; struct_pointer = &Book1; struct_pointer->title; // 訪問結構成員 |
A函數(shù)被當作參數(shù)傳入B函數(shù),那么A函數(shù)被叫做回調函數(shù),如下表所示:
形式一 | |
回調函數(shù) | int one_def(void) { return 0; } void def_name(int (*get_def)(void)) { get_def(); } def_name(one_def); |
字符串實際上是使用空字符 \0 結尾的一維字符數(shù)組,初始化時默認添加\0到末尾,操作字符串時,可使用stdio.h頭文件,提供函數(shù)如下表:
作用 | |
strcpy(s1, s2); | 復制字符串 s2 到字符串 s1 |
strcat(s1, s2); | 連接字符串 s2 到字符串 s1 的末尾 |
strlen(s1); | 返回字符串 s1 的長度 |
strcmp(s1, s2); | 如果 s1 和 s2 是相同的,則返回 0;如果 s1<s2 則返回小于 0;如果 s1>s2 則返回大于 0 |
strchr(s1, ch); | 返回一個指針,指向字符串 s1 中字符 ch 的第一次出現(xiàn)的位置 |
strstr(s1, s2); | 返回一個指針,指向字符串 s1 中字符串 s2 的第一次出現(xiàn)的位置 |
用戶自定義數(shù)據(jù)類型,可存儲不同類型的數(shù)據(jù)項,如下表所示:
形式一 | 形式二 | 形式三 | 形式四 | 形式五 | 形式六 | |
定義結構 | struct { int a; char b; double c; } s1; | struct SIMPLE { int a; char b; double c; }; struct SIMPLE t1, t2[20], *t3; | typedef struct { int a; char b; double c; } Simple2; Simple2 u1, u2[20], *u3; | struct COMPLEX { char string[100]; struct SIMPLE a; }; | struct NODE { char string[100]; struct NODE *next_node; }; | struct B; struct A { struct B *partner; //other members; }; struct B { struct A *partner; //other members; }; |
初始化結構 | struct Books { char title[50]; char author[50]; char subject[100]; int book_id; } book = {'C 語言', 'RUNOOB', '編程語言', 123456}; | |||||
訪問結構 | strcpy( Book1.title, 'C Programming'); book.book_id = 6495407; | |||||
結構作為函數(shù)參數(shù) | void printBook( struct Books book ); |
在相同的內存位置存儲不同的數(shù)據(jù)類型,需要使用共用體,如下表所示:
形式一 | |
定義共用體 | union Data { int i; float f; char str[20]; } data; union Data data; printf( 'Memory size occupied by data : %d\n', sizeof(data)); // 20 |
訪問共用體 | data.i = 10; data.f = 220.5; strcpy( data.str, 'C Programming'); printf( 'data.i : %d\n', data.i); //因為共用存儲,因此data.i的值并不是10 |
有些信息在存儲時,并不需要占用一個完整的字節(jié),而只需占幾個或一個二進制位。例如在存放一個開關量時,只有 0 和 1 兩種狀態(tài),用 1 位二進位即可。為了節(jié)省存儲空間,并使處理簡便,C 語言又提供了一種數(shù)據(jù)結構,稱為'位域'或'位段',如下表所示:
形式一 | 形式一 | 備注 | |
位域聲明 | struct { int a : 1; int b : 2; } bit_name; | struct name { int a : 1; int b : 2; int : 3; } bit_name; | 這樣設計規(guī)定了a的存儲空間為1,b的存儲空間為2,空域占了3字節(jié)不能被使用 |
使用位域 | bit_name.a=1; // 需要在范圍內賦值 |
預處理器是一個文本替換工具,指示編譯器在實際編譯之前完成所需的預處理,如下表所示:
形式一 | 備注 | ||
預處理指令 | #define | #define MAX_ARRAY_LENGTH 20 | 定義宏/聲明變量 |
#include | #include <stdio.h> #include 'myheader.h' | 包含一個源代碼文件 | |
#undef | #undef FILE_SIZE #define FILE_SIZE 42 | 取消已定義的宏 | |
#ifdef | #ifdef DEBUG /* Your debugging statements here */ #endif | 如果宏已經(jīng)定義,則返回真 | |
#ifndef | #ifndef MESSAGE #define MESSAGE 'You wish!' #endif | 如果宏沒有定義,則返回真 | |
#if | 如果給定條件為真,則編譯下面代碼 | ||
#else | #if 的替代方案 | ||
#elif | 如果前面的 #if 給定條件不為真,當前條件為真,則編譯下面代碼 | ||
#endif | 結束一個 #if……#else 條件編譯塊 | ||
#error | 當遇到標準錯誤時,輸出錯誤消息 | ||
#pragma | 使用標準化方法,向編譯器發(fā)布特殊的命令到編譯器中 | ||
預定義宏 | __DATE__ | 來源stdio.h頭文件,可直接使用的宏,但不能修改,代表當前日期 | |
__TIME__ | 當前時間 | ||
__FILE__ | 當前文件名 | ||
__LINE__ | 當前行號 | ||
__STDC__ | 當編譯器以 ANSI 標準編譯時,則定義為 1 | ||
預處理器運算符 | \ | 一條宏可使用\換行 | |
# | #define message_for(a, b) \ printf(#a ' and ' #b ': We love you!\n') | 可對message_for進行傳參 | |
## | #include <stdio.h> #define tokenpaster(n) printf ('token' #n ' = %d', token##n) int main(void) { int token34 = 40; tokenpaster(34); return 0; } // token34 = 40 | 允許在宏定義中兩個獨立的標記被合并為一個標記 | |
defined() | #include <stdio.h> #if !defined (MESSAGE) #define MESSAGE 'You wish!' #endif int main(void) { printf('Here is the message: %s\n', MESSAGE); return 0; } | 如果MESSAGE被定義過,則defined返回真 | |
參數(shù)化的宏 | #include <stdio.h> #define MAX(x,y) ((x) > (y) ? (x) : (y)) int main(void) { printf('Max between 20 and 10 is %d\n', MAX(10, 20)); return 0; } // Max between 20 and 10 is 20 | 使用參數(shù)化的宏來模擬函數(shù) |
頭文件能夠提供接口供外部調用,如下表所示:
形式一 | 形式二 | 備注 | |
定義頭文件 | #ifndef HEADER_FILE #define HEADER_FILE ... #endif | ||
引用頭文件 | #include <file> | #include 'file' | <>用于標準庫包含,''用于私有庫包含 |
有條件引用 | #if SYSTEM_1 # include 'system_1.h' #elif SYSTEM_2 # include 'system_2.h' #elif SYSTEM_3 ... #endif | #define SYSTEM_H 'system_1.h' ... #include SYSTEM_H | 指定在不同的操作系統(tǒng)上使用的配置參數(shù)可以使用宏的條件語句,這樣兼容性更強 |
強制類型轉換是把變量從一種類型轉換為另一種數(shù)據(jù)類型,如下表所示:
形式一 | 備注 | |
強制類型轉換 | int sum = 17, count = 5; double mean; mean = (double) sum / count; | char可以和int直接相加(隱式轉換),這中間產(chǎn)生的類型轉換,被稱為整數(shù)提升 |
常用的算數(shù)轉換 | 算術中產(chǎn)生的隱式轉換 | 轉換時將遵從如下優(yōu)先級: long double double float unsigned long long long long unsigned long long unsigned int int |
遞歸指的是在函數(shù)的定義中使用函數(shù)自身的方法,如下表所示:
形式一 | 備注 | |
數(shù)的階乘 | #include <stdio.h> double factorial(unsigned int i) { if(i <= 1) { return 1; } return i * factorial(i - 1); } int main() { int i = 15; printf('%d 的階乘為 %f\n', i, factorial(i)); return 0; } | 遞歸函數(shù)的要點是定義一個從函數(shù)退出的條件 |
斐波那契數(shù)列 | #include <stdio.h> int fibonaci(int i) { if(i == 0) { return 0; } if(i == 1) { return 1; } return fibonaci(i-1) + fibonaci(i-2); } int main() { int i; for (i = 0; i < 10; i++) { printf('%d\t\n', fibonaci(i)); } return 0; } |
要給函數(shù)傳入可變數(shù)量的參數(shù),如下表所示:
形式一 | 備注 | |
可變參數(shù) | int func(int, ... ) {...} | 需要使用 stdarg.h 頭文件,該文件提供了實現(xiàn)可變參數(shù)功能的函數(shù)和宏 |
例子 | #include <stdio.h> #include <stdarg.h> double average(int num,...) { va_list valist; double sum = 0.0; int i; /* 為 num 個參數(shù)初始化 valist */ va_start(valist, num); /* 訪問所有賦給 valist 的參數(shù) */ for (i = 0; i < num; i++) { sum += va_arg(valist, int); } /* 清理為 valist 保留的內存 */ va_end(valist); return sum/num; } int main() { printf('Average of 2, 3, 4, 5 = %f\n', average(4, 2,3,4,5)); printf('Average of 5, 10, 15 = %f\n', average(3, 5,10,15)); } |
想要從外部控制程序,而不是在代碼內對這些值進行硬編碼時,如下表所示:
形式一 | 備注 | |
命令行參數(shù) | #include <stdio.h> int main( int argc, char *argv[] ) { if( argc == 2 ) { printf('The argument supplied is %s\n', argv[1]); } else if( argc > 2 ) { printf('Too many arguments supplied.\n'); } else { printf('One argument expected.\n'); } } | argc 是指傳入?yún)?shù)的個數(shù),argv[] 是一個指針數(shù)組,指向傳遞給程序的每個參數(shù) |
1.、C與C++
C++是C語言的超集,即包含C語言全部語法,并基于此進行了擴展。相對C語言,C++面向對象,而C面向過程,即使如此,C++本質上是C。C++的程序文件后綴為cpp,而C程序文件的后綴是c。
2、基本語法
在C的基礎上,引入了對象、類、方法、即時變量,而方法就是C函數(shù)。而即時變量指的是對象內的變量,他跟隨著對象的生命周期。在C++中引入了命名空間的概念,常用的命名空間有”using namespace std; “,為的是避免地會出現(xiàn)變量或函數(shù)的命名沖突。
這里的差異指的是C++基于C的新增,即C有的,C++都有(貌似存在差集,只能說以前C++是 C的超集,現(xiàn)在語法上存在差集,以后可能會漸行漸遠),就不再重復累述。
(1)布爾型
bool :有兩個值,true 值代表真,false 值代表假
(2)寬字符型
wchar_t : 一個寬字符暫用2 或 4 個字節(jié),如果常量以 L(僅當大寫時)開頭,則表示它是一個寬字符常量(例如 L'x'),此時它必須存儲在 wchar_t 類型的變量中。否則,它就是一個窄字符常量(例如 'x'),此時它可以存儲在 char 類型的簡單變量中。
新增2個常量修飾符:
(1)volatile
修飾符 volatile 告訴編譯器不需要優(yōu)化volatile聲明的變量,讓程序可以直接從內存中讀取變量。對于一般的變量編譯器會對變量進行優(yōu)化,將內存中的變量值放在寄存器中以加快讀寫效率。
(2)restrict
由 restrict 修飾的指針是唯一一種訪問它所指向的對象的方式。只有 C99 增加了新的類型限定符 restrict。
(1)mutable
mutable 說明符僅適用于類的對象,它允許對象的成員替代常量。也就是說,mutable 成員可以通過 const 成員函數(shù)修改。
(2)thread_local
使用 thread_local 說明符聲明的變量僅可在它在其上創(chuàng)建的線程上訪問。 變量在創(chuàng)建線程時創(chuàng)建,并在銷毀線程時銷毀。 每個線程都有其自己的變量副本。
(1)二進制運算符(在C中也可用,這里做補充)
<< : 左移運算符
>> :右移運算符
(2)逗號運算符
, : 會順序執(zhí)行一系列運算。整個逗號表達式的值是以逗號分隔的列表中的最后一個表達式的值。
(3)成員運算符
. :用于引用類、結構和共用體的成員
(4)強制轉換運算符
const_cast 運算符用于修改類型的 const / volatile 屬性。除了 const 或 volatile 屬性之外,目標類型必須與源類型相同。這種類型的轉換主要是用來操作所傳對象的 const 屬性,可以加上 const 屬性,也可以去掉 const 屬性。
dynamic_cast 在運行時執(zhí)行轉換,驗證轉換的有效性。如果轉換未執(zhí)行,則轉換失敗,表達式 expr 被判定為 null。dynamic_cast 執(zhí)行動態(tài)轉換時,type 必須是類的指針、類的引用或者 void*,如果 type 是類指針類型,那么 expr 也必須是一個指針,如果 type 是一個引用,那么 expr 也必須是一個引用。
reinterpret_cast 運算符把某種指針改為其他類型的指針。它可以把一個指針轉換為一個整數(shù),也可以把一個整數(shù)轉換為一個指針。
static_cast 運算符執(zhí)行非動態(tài)轉換,沒有運行時類檢查來保證轉換的安全性。例如,它可以用來把一個基類指針轉換為派生類指針。
(1)匿名函數(shù)
形式一 | 形式二 | 形式三 | 形式四 | |
匿名函數(shù) | []{ ++global_x; } | [](int x, int y){ return x < y ; } | [](int x, int y) -> int { int z = x + y; return z + x; } | [this]() { this->someFunc(); }(); |
(1)string類類型
由C++ 標準庫提供,引入(#include <string>),使用(string str1 = 'runoob';)。
引用變量是一個別名,也就是說,它是某個已存在變量的另一個名字。一旦把引用初始化為某個變量,就可以使用該引用名稱或變量名稱來指向變量。形式如 int& r = i; 表明r與i共用存儲地址。
引用 | 樣式一 | 備注 |
聲明引用 | int i = 17; int& r = i; | 引用與指針的不同: 1、不存在空引用。引用必須連接到一塊合法的內存 2、一旦引用被初始化為一個對象,就不能被指向到另一個對象。指針可以在任何時候指向到另一個對象 3、引用必須在創(chuàng)建時被初始化。指針可以在任何時間被初始化 |
類是對C函數(shù)的二次封裝,讓C函數(shù)有了集合,形成了對象,如下表所示:
形式一 | 形式二 | |
定義類 | class Box { public: double length; // 長度 double breadth; // 寬度 double height; // 高度 double getVolume(void) { return length * breadth * height; } }; | class Box { public: double length; // 長度 double breadth; // 寬度 double height; // 高度 double getVolume(void) }; double Box::getVolume(void) { return length * breadth * height; } |
聲明類 | Box myBox; // 創(chuàng)建一個對象 | |
使用類 | myBox.getVolume(); // 調用該對象的成員函數(shù) |
類的訪問有特定的修飾符,如下表所示:
訪問方式 | 備注 | |
public | 可供外部直接訪問 | |
private | 外部不能訪問 | 沒有被修飾的成員均為私有成員 |
protected | 外部不能訪問,但子類能訪問 |
類的構造函數(shù)會在創(chuàng)建類的新對象時執(zhí)行,而析構函數(shù)在銷毀類的對象時執(zhí)行,如下表所示:
樣式一 | 樣式二 | 備注 | |
構造函數(shù) | class Line { public: Line(); //構造函數(shù) } Line::Line(void) {} | class Line { public: Line(); //構造函數(shù) } Line::Line( double len): length(len) {} | 構造函數(shù)的名稱與類的名稱是完全相同的,可帶參數(shù);帶參數(shù)時,如果沒有像樣式二那樣已經(jīng)傳參,那么初始化要輸入?yún)?shù),如:Line line(10.0);多個字段參數(shù)化時,可以采用如下方式: C::C( double a, double b, double c): X(a), Y(b), Z(c){} |
析構函數(shù) | class Line { public: ~Line(); //析構函數(shù) } Line::~Line(void) {} | 析構函數(shù)的名稱與類的名稱是完全相同的,只是在前面加了個波浪號(~)作為前綴,它不會返回任何值,也不能帶有任何參數(shù)。 |
拷貝構造函數(shù)在創(chuàng)建對象時,是使用同一類中之前創(chuàng)建的對象來初始化新創(chuàng)建的對象,類似于python中的單例模式,如下表所示:
樣式一 | 備注 | |
拷貝構造函數(shù) | class Line { public: int getLength( void ); Line( int len ); // 簡單的構造函數(shù) Line( const Line &obj); // 拷貝構造函數(shù) ~Line(); // 析構函數(shù) private: int *ptr; }; | obj 是一個對象引用,該對象是用于初始化另一個對象的 |
類的友元函數(shù)是定義在類外部,但有權訪問類的所有私有(private)成員和保護(protected)成員。友元可以是一個函數(shù),該函數(shù)被稱為友元函數(shù);友元也可以是一個類,該類被稱為友元類,在這種情況下,整個類及其所有成員都是友元。如下表所示:
樣式一 | 備注 | |
友元函數(shù) | class Box { public: friend void printWidth( Box box ); }; void printWidth( Box box ){} | 友元函數(shù)不是任何類的成員函數(shù) |
內聯(lián)函數(shù)在編譯時,編譯器會把該函數(shù)的代碼副本放置在每個調用該函數(shù)的地方。對內聯(lián)函數(shù)進行任何修改,都需要重新編譯函數(shù)的所有客戶端,因為編譯器需要重新更換一次所有的代碼,否則將會繼續(xù)使用舊的函數(shù)。如下表所示:
樣式一 | |
內聯(lián)函數(shù) | inline int Max(int x, int y) { return (x > y)? x : y; } |
this 指針來訪問自己的地址,類似于python中的self,如下表所示:
樣式一 | |
this指針 | class Box { public: // 構造函數(shù)定義 Box(double l=2.0, double b=2.0, double h=2.0) { cout <<'Constructor called.' << endl; length = l; breadth = b; height = h; } double Volume() { return length * breadth * height; } int compare(Box box) { return this->Volume() > box.Volume(); } private: double length; // Length of a box double breadth; // Breadth of a box double height; // Height of a box }; |
當一個指針指向類時,訪問方式使用 -> 符號,如下表所示:
樣式一 | |
指向類的指針 | class Box { public: // 構造函數(shù)定義 Box(double l=2.0, double b=2.0, double h=2.0) { cout <<'Constructor called.' << endl; length = l; breadth = b; height = h; } double Volume() { return length * breadth * height; } private: double length; // Length of a box double breadth; // Breadth of a box double height; // Height of a box }; Box Box1(3.3, 1.2, 1.5); // Declare box1 Box Box2(8.5, 6.0, 2.0); // Declare box2 Box *ptrBox; // 指向類的指針 ptrBox = &Box1; ptrBox->Volume(); // 訪問方式 |
類的靜態(tài)成員在所有對象中是共享的,如下表所示:
樣式一 | |
靜態(tài)成員變量 | static int objectCount; |
靜態(tài)成員函數(shù) | static int getCount() { return objectCount; } |
繼承允許我們依據(jù)另一個類來定義一個類,這使得創(chuàng)建和維護一個應用程序變得更容易,如下表所示:
樣式一 | 樣式二 | 備注 | |
繼承 | // 基類 class Animal { // eat() 函數(shù) // sleep() 函數(shù) }; //派生類(子類) class Dog : public Animal { // bark() 函數(shù) }; | // 基類 Shape class Shape { }; // 基類 PaintCost class PaintCost { }; // 派生類 class Rectangle: public Shape, public PaintCost { public: int getArea() { return (width * height); } }; | 繼承方式有3種,public、protected 或 private,缺省則默認private |
我們幾乎不使用 protected 或 private 繼承,通常使用 public 繼承。當使用不同類型的繼承時,遵循以下幾個規(guī)則:
一個派生類繼承了所有的基類方法,但下列情況除外:
重載聲明是指一個與之前已經(jīng)在該作用域內聲明過的函數(shù)或方法具有相同名稱的聲明,但是它們的參數(shù)列表和定義(實現(xiàn))不相同。如下表所示:
樣式一 | 備注 | |
重載 | class Box { public: double getVolume(void) { return length * breadth * height; } void setLength( double len ) { length = len; } void setBreadth( double bre ) { breadth = bre; } void setHeight( double hei ) { height = hei; } // 重載 + 運算符,用于把兩個 Box 對象相加 Box operator+(const Box& b) { Box box; box.length = this->length + b.length; box.breadth = this->breadth + b.breadth; box.height = this->height + b.height; return box; } private: double length; // 長度 double breadth; // 寬度 double height; // 高度 }; | 類似于python的魔術方法 |
多態(tài)按字面的意思就是多種形態(tài)。當類之間存在層次結構,并且類之間是通過繼承關聯(lián)時,就會用到多態(tài)。C++ 多態(tài)意味著調用成員函數(shù)時,會根據(jù)調用函數(shù)的對象的類型來執(zhí)行不同的函數(shù)。如下表所示:
樣式一 | 樣式二 | |
多態(tài) | class Shape { protected: int width, height; public: Shape( int a=0, int b=0) { width = a; height = b; } virtual int area() // 虛函數(shù)(動態(tài)鏈接),允許多態(tài)(允許子類重寫該函數(shù)) { 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); } }; | class Shape { protected: int width, height; public: Shape( int a=0, int b=0) { width = a; height = b; } // 純虛函數(shù),沒有具體實現(xiàn) virtual int area() = 0; }; |
聯(lián)系客服