編輯:劉風琛css
最初編寫日期:2020年4月11日下午 最新更新日期:2020年9月20日上午ios
標註:c++
P107
:類和對象給一段內存起名,方便使用。程序員
用於記錄程序中不可更改的數據。算法
#define 常量名 常量值
const 數據類型 常量名=常量值
sizeof()
能夠返回當前數據類型所佔內存大小。編程
強制轉換
語法:(數據類型)被轉變量
舉例:windows
int main(){ char ch = 'a'; cout<<(int)ch<<endl; return 0; }
輸出結果:97
(字符a的ASCII碼)數組
轉義字符
轉義字符用反斜槓\
表示,能夠用來表示ASCII碼的特殊值。安全
轉義字符 | 含義 | ASCII碼值 |
---|---|---|
\a | 警報 | 007 |
\b | 退格(BS),將當前位置移到前一列 | 008 |
\f | 換頁(FF),將當前位置移到下頁開頭 | 012 |
\n | 換行(LF),將當前位置移到下一行開頭 | 010 |
\r | 回車(CR),將當前位置移到本行開頭 | 013 |
C++中能夠用如下方式表示整型,區別在於所佔內存空間不一樣app
數據類型 | 佔用空間 | 取值範圍 |
---|---|---|
short(短整型) | 2字節 | -215~215-1 |
int(整型) | 4字節 | -231~231-1 |
long(長整型) | windows爲4字節;Linux 32位4字節,64位8字節 | -231~231-1 |
long long(長長整型) | 8字節 | -263~263-1 |
浮點型分爲如下兩種:
數據類型 | 佔用空間 | 取值範圍 |
---|---|---|
float(單精度) | 4字節 | 7位有效數字 |
double(雙精度) | 8字節 | 15~16位有效數字 |
表示單個字符的數據類型,只佔一個字節。
char ch = 'a'
表示一串字符,能夠有兩種表示方式。
C語言中經常使用方式(數組):char 變量名[] = "abcde"
示例:
int main(){ char str[] = "Hello world!"; cout<<str<<endl; return 0; }
當前標準方式:string 變量名 = "abcde"
示例:
#include <string> int main(){ string str = "Hello World!"; cout<<str<<endl; return 0; }
string
須要引入頭文件:#include <string>
表明"true(1)"或者"false(0)",表示邏輯。
包括四則運算,取餘等方法。
四則運算注意事項
/
"注意不要和反斜槓"\
"混淆。取模運算
%
"遞增和遞減
賦值運算符
=
、+=
、-=
、*=
、/=
、%=
。int main(){ int a=1; a=3; //此時a=3; a+=2; //此時a=5 a-=3; //此時a=2 a*=2; //此時a=4 a/=2; //此時a=2 a%=1; //此時a=0 cout<<a<<endl; return 0; }
比較運算符
包括==
、>=
、<=
、!=
、>
、<
。
邏輯運算符
!
、與&&
、或||
。三目運算符
表達式1 ? 表達式2 : 表達式3
int main(){ int a=1,b=10,c=0; //用法一 c = (a > b ? a : b); //括號能提升三目運算的優先級防止運行出錯 //將a和b中值較大的賦值給c //用法二 (a > b ? a : b) = 999; //把999賦給a和b中較大的變量 return 0; }
就是從頭至尾順序執行,沒啥可記的。
判斷選擇,能夠實現跳過或者分支。
if語句
用法一:if(條件){知足條件執行的代碼塊}
int main(){ int score; cout<<"Please input your score:"; cin>>score; if (score>=600){ cout<<"Good!"; } return 0; }
用法二:if(條件){知足條件執行的代碼塊}else{不知足時執行的代碼塊}
else
爲可選分支,刪除後和用法一相同。int main(){ int score; cout<<"Please input your score:"; cin>>score; if (score>=600){ cout<<"Good!"; }else{ cout<<"Bad!"; } return 0; }
用法三:if(條件1){知足條件執行的代碼塊}else if(條件2){不知足條件1但知足條件2時執行的代碼塊}
-。
else
和 else if
爲可選分支.else if
可並列屢次使用int main(){ int score; cout<<"Please input your score:"; cin>>score; if (score>=600){ cout<<"Good!"; } else if(score>=400){ cout<<"Bad!"; } else{ cout<<"So Bad!"; } return 0; }
用法四:if語句的嵌套,我認爲沒啥高級的,因此不記了。
switch語句
int main(){ int level; cin>>level; switch(level){ case 1: cout<<"Good"; break; case 2: cout<<"Normal"; break; case 3; cout<<"Bad"; break; default : cout<<"非法輸入!請輸入1~3之間的整數。"; break; } return 0; }
循環執行代碼塊。
條件知足時不斷循環執行指定代碼塊,不然跳出循環。
用法:while(條件){條件爲真時循環執行的代碼塊}
注意:
break
跳出循環。示例:
int main(){ int a=0; while(a<10){ a++; cout<<a; } return 0; }
用法:do{代碼塊}while(條件);
注意:
while
相同。示例:
int main(){ int a=0; do{ a++; cout<<a<<endl; } while(a<10); return 0; }
用法:for(起始表達式;條件表達式;末尾表達式){循環代碼塊}
注意:可使用break
跳出循環。
示例:
int main(){ for(int i=1;i<10;i++){ cout<<i<<endl; } return 0; }
用於跳出或者移動當前結構中的運行位置。
做用:在循環語句中跳過餘下還沒有執行的語句,直接進入下一次循環。
示例:
int main(){ for (int i=1;i<=10;i++) { cout<<i<<endl; continue; cout<<"這段不被輸出\n"; } return 0; }
做用:能夠跳轉到任意標記的位置。
示例:
int main(){ for(int i=1;i<=10;i++){ cout<<"這是第一句話\n"; cout<<"這是第二句話\n"; goto flag; cout<<"這句話咱們不要了\n"; flag: cout<<"這是第三句話\n"; } return 0; }
數組就是一個集合,裏邊存放了一組相同類型的數據。
一維數組的定義方式:
數據類型 數組名[數組長度];
數據類型 數組名 [數組長度]={值1,值2,...,值n};
數據類型 數組名[]={值1,值2,...,值n};
訪問格式:array [0]
注意事項:
示例:
int main(){ int arr[5]={1,2,3,4};//只初始化了前四個,第五個值默認初始化爲0 for(int i=0;i<=4;i++) { cout<<arr[i]<<endl; } arr[4]=5; //這是對數組中未初始化的第5個值賦值 cout<<arr[0]; return 0; }
補充:
sizeof(數組名/數組名[])
函數)cout<<array;
)一維數組的倒置示例:
int main(){ int arr [5]={1,2,3,4,5};//建立一個數組 int temp,a,b; a=0;b=sizeof(arr)/sizeof (arr[0])-1;//b爲經過計算得出的數組中元素數量減1 while(a<b){ temp=arr[a]; arr[a]=arr[b]; arr[b]=temp; a++;b--; } b=sizeof(arr)/sizeof (arr[0]);//爲了節省內存,將b重置爲數組元素個數 for(int i = 1;i<=b;i++){ //循環b次,依次輸出數組中每一個元素的值 cout<<arr[i-1]<<endl; } return 0; }
一維數組的順序排列示例(冒泡排序):
int main(){ int arr[5]={1,5,2,3,4}; for (int i = 0;i < 5;i++){ for(int j = 0;j<(5-i-1);j++){ if (arr[j]>arr[j+1]){ int temp; temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } } for (int q = 1; q<=5;q++){ cout<<arr[q-1]<<endl; } return 0; }
定義方式:
數據類型 數組名 [行數][列數]={{數值1,數值2...},{數值n,數值n+1...}};
數據類型 數組名 [行數][列數];
數據類型 數組名 [行數][列數]={數據1,數據2,數據3,數據4};
數據類型 數組名 [][列數]={數據1,數據2,數據3,數據4};
示例:
int main(){ //這是建立二維數組最直觀的形式 int arr[2][3]={ {1,2,3}, {4,5,6} }; //使用for循環嵌套遍歷輸出二位數組中每一個元素 for (int i=0;i<2;i++){ for (int j=0;j<3;j++){ cout<<arr[i][j]<<" "; } cout<<endl; } return 0; }
二維數組名的用途
sizeof(數組名/數組名[]/數組名[][])
)cout<<array;
)注意:
函數就是一個程序塊,能夠方便的進行調用,能很好的減小代碼量,一個較大的程序每每分紅好多模塊,每一個模塊實現特定功能。
函數的定義示例:
返回值類型 函數名(形參) { 程序代碼塊; retuen 返回值表達式; }
注意:
函數名(參數)
形參
,是一個形式,調用的是使用函數時傳遞的實參
。語法返回值類型 函數名(形參)
注意:
示例:
int max(int num1,int num2); //函數max的聲明 int main(){ cout<<max(100,101)<<endl; return 0; } int max(int num1,int num2){ //函數的定義 return num1 > num2 ? num1:num2; } //函數定義在main函數後須要在main函數前聲明。
爲了防止單文件形勢下代碼量過大。
要素:
示例:
文件結構:
代碼示例:
main.cpp
#include <iostream> #include "max.h" using namespace std; int main(){ cout<<max(100,101)<<endl; return 0; }
max.h
#include <iostream> using namespace std; int max(int num1,int num2);
max.cpp
#include "max.h" int max(int num1,int num2){ return num1 > num2 ? num1:num2; }
輸出結果:100
語法:返回值類型 函數名(參數名=默認值);
注意:
示例:
void print(int a=10,int b=20,int c=30){ //給全部選項都設置了默認參數 cout<<a+b+c<<endl; } int main() { print(1,2,3);//調用函數是傳遞參數 //輸出6 print();//調用函數時不傳遞參數,使用默認參數 //輸出60 return 0; }
語法:返回值類型 函數名 (數據類型);
示例:
void print(int = 10){ //只有數據類型,沒有變量名就是佔位參數 cout<<"Hello World!"; } int main(){ print(); //由於佔位參數具備默認值,因此此處無需傳遞,不然必須傳遞一個相應類型的參數 }
意義:函數名能夠相同,提升函數複用性。
條件:
參數名
或參數個數
或參數順序
不一樣。注意:函數的返回值不可用做函數重載的條件。
示例:
void print(){ cout<<"print()函數被調用\n"; } void print(int a){ cout<<"print(int a)函數被調用\n"; } int main() { print();//print()函數被調用 print(1);//print(int a)函數被調用 //其餘例如參數名,參數個數,參數順序不一樣 同理 return 0; }
常量引用
示例:
void print(int& a){ cout<<"print()函數被調用\n";//若是傳入數字1,則爲int& a = 1 不合法 } void print(const int& a){ //至關於const int& a = 1 合法 cout<<"print(int a)函數被調用\n"; } int main() { int a=1; print(a); print(1); return 0; }
引入默認值致使的二義性
示例:
void print(int a){ cout<<"print()函數被調用\n"; } void print(int a,int b=1){ cout<<"print(int a,int b=1)函數被調用\n"; } int main() { print(1);//這個會報錯,由於產生了二義性 print(1,1);//會調用print(int a,int b=1)函數 return 0; }
能夠經過指針間接訪問內存地址。
數據類型 * 指針變量名
讓指針記錄一個地址:
語法:指針變量名 = &變量名
注意:
&
爲取址符,能夠獲取當前內存地址。指針指向函數:
返回值 (*指針名)(參數列表);
指針的使用:
經過解引用
影響指針指向內存區域所儲存的值。
示例:
int main(){ int a = 10; int * p; //定義一個指針p p=&a; //將變量a的地址賦給指針p //int * p = &a; //這個方式能夠將定義和賦值寫在一塊兒 *p=1000; //使用解引用影響指針p指向的內存區域,也就是變量a cout<<a<<endl; cout<<*p<<endl; //經過輸出展現指針所產生的影響 return 0; }
int * p = NULL
三種方式:
const int * p = NULL
int * const p = NULL
const int * const p=NULL
用指針操做數組。
示例:
int main(){ int arr[5]={1,2,3,4,5}; int * p=arr; //將指針指向數組在內存中的首地址 for (int i=0;i<5;i++){ cout<<*p<<endl; //輸出指針p指向的值 p++; //每次循環將指針p向後偏移4字節,實現指針在數組中的遍歷 } return 0; }
利用指針做爲函數的參數能夠修改實參的值。
示例:
void swap(int *p1,int *p2){ //聲明一個函數用來交換兩個變量的值,形參爲兩個指針 //這部分直接影響了指針所指向的內存空間,也就是main函數中a,b兩個變量的值 int temp=*p1; *p1=*p2; *p2=temp; } int main(){ int a=1,b=2; cout<<"a="<<a<<" b="<<b<<endl; swap(&a,&b); //引用函數,實參爲兩個變量的地址 cout<<"a="<<a<<" b="<<b<<endl; return 0; }
利用冒泡循環對數組排序。
int bubbleSort(int * arr,int len){ //使用函數封裝冒泡循環的算法 for (int i = 0;i<len;i++){ for(int j=0;j<len-i-1;j++){ if(arr[j]>arr[j+1]){ int temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } } } int main(){ int arr []={1,5,3,2,7,8,3,5,2}; int len=sizeof(arr)/sizeof (arr[0]); //獲取數組的元素數量 bubbleSort(arr,len); //調用函數,第一個實參爲arr數組的內存地址 for(int i = 0;i<len;i++){ cout<<arr[i]<<endl; } }
容許用戶建立自定義數據類型
,儲存不一樣的數據類型。
語法:struck 結構體名 { 結構體成員列表 };
建立變量方式:
使用變量的屬性
變量名.屬性
示例:
struct student //定義結構體(全局),struct關鍵字不可省略 { string name; int age; int score; }s3; //此處s3爲使用方法三建立的結構體變量 int main(){ //方法一 struct student s1={"Maicss",19 , 650 } ; //struct關鍵字能夠省略 cout<<"name:"<<s1.name<<"\tage:"<<s1.age<<"\tscore:"<<s1.score<<endl; //方法二 struct student s2; //struct關鍵字能夠省略 s2.name="qian"; s2.age=18; s2.score=600; cout<<"name:"<<s2.name<<"\tage:"<<s2.age<<"\tscore:"<<s2.score<<endl; //方法三 //建立結構體變量在定義結構體以後 s3.name="son"; s3.age=1; s3.score=700; cout<<"name:"<<s3.name<<"\tage:"<<s3.age<<"\tscore:"<<s3.score<<endl; return 0; }
做用:將自定義的結構體放入數組中方便維護。
語法:struck 結構體名 數組名[成員數] = { { } , { } , { } }
示例:
struct student { //定義一個結構體 string name; int age; int score; }; int main() { //建立一個結構體數組 struct student stuarr[3]{ {"Maicss",19,100}, {"Max",20,99}, {"Pig",10,30} }; //給結構體數組中第三個成員的score修改成98 stuarr[2].score =98; //遍歷輸出結構體數組全部成員屬性 for (int i=0 ;i<3;i++){ cout<<"name:"<<stuarr[i].name<<"\tage:"<<stuarr[i].age<<"\tscore:"<<stuarr[i].score<<endl; } return 0; }
做用:經過指針訪問結構體中的成員。
利用操做符->
能夠經過結構體指針訪問結構體屬性。
示例:
struct student { //定義一個結構體 string name; int age; int score; }; int main() { //建立一個結構體數組 student s{"Maicss",19,100}; //建立一個結構體指針 student * p = &s; //經過指針讀取結構體變量屬性 cout<<"name:"<<p->name<<"\tage:"<<p->age<<"\tscore:"<<p->score<<endl; return 0; }
做用:讓一個結構體成爲另外一個結構體的成員。
示例:
struct student { //定義一個結構體 string name; int age; int score; }; struct teacher { //定義另外一個結構體 string name; int id; int age; student std; }; int main() { //建立一個結構體變量 student std1 {"max",18,100}; //建立另外一個結構體變量 teacher thr1 {"maicss",197835,23,std1}; //建立一個結構體指針 teacher * p = &thr1; //修改老師maicss的學生max的年齡爲19 thr1.std.age=19; //經過指針讀取結構體變量屬性 cout<<"name:"<<p->name <<"\tID:"<<p->id <<"\tage:"<<p->age <<"\tstudent:"<<p->stds.name //讀取嵌套在teacher結構體中的student的屬性 <<"\tstudentAge:"<<p->stds.age //查看更改後的學生年齡 <<endl; return 0; }
值傳遞
指針傳遞
const 保護
示例:
struct student { //定義一個結構體 string name; int age; int score; }; void print1(student a){ //結構體在函數參數中經過值傳遞 cout<<"name:"<<a.name<<" age:"<<a.age<<" score:"<<a.score<<endl; } void print2(student * p){ //結構體在函數參數中經過指針傳遞 p->age=100; //經過指針修改結構體屬性的值能夠影響到實參 cout<<"name:"<<p->name<<" age:"<<p->age<<" score:"<<p->score<<endl; } int main() { //建立一個結構體變量 student std1 {"max",18,100}; //建立一個結構體指針 student * p =&std1; //調用函數進行輸出 print1(std1); //值傳遞 print2(&std1);//指針傳遞 cout<<"name:"<<std1.name<<" age:"<<std1.age<<" score:"<<std1.score<<endl; //驗證print2函數的修改 return 0; }
程序編譯後,生成exe
可執行程序,未執行該程序前分爲兩個區域。
棧區
由編譯器自動分配和釋放,存放函數的參數值,局部變量等。
注意:不要返回棧區的地址,棧區開闢的數據由編譯器自動釋放。
棧區的數據在函數執行完後自動釋放。
示例:
int* integer(){ int a=1; return &a; //返回局部變量a的內存地址 } int main() { int * p=integer(); //將指針p指向局部變量a的地址 cout <<*p<< endl; //第一次解引用p //這裏之因此會輸出a是由於編譯器爲程序保留了一次內存 cout <<*p<< endl;//第二次解引用p //編譯器再也不爲程序保留,因此再也不是原來的數值 return 0; }
堆區
由程序員分配和釋放,若程序員不釋放,程序結束時由系統回收。
使用new
在堆區開闢內存。
new 數據類型
使用delect
釋放內存。
delect 指針
爲了防止出現野指針
,在堆區內存空間被釋放時要將指向該內存的指針指向NULL
。
int main() { int * p = new int(10); //使用new開闢一塊內存儲存整數10並將地址給指針p int * p2 = new int[10]; //建立一個數組 cout<<*p<<endl;//解引用指針p結果爲10 //賦值部分省略 delete p;//釋放內存 delete[] p2;//釋放數組 }
引用的本質是指針常量。
做用:給變量起別名。
語法:&別名=原名
注意事項:
做用:就像指針同樣,能夠影響到實參。
示例:
//建立一個交換函數 void swap(int &a,int &b){ //使用引用傳遞參數 int temp; temp=a; a=b; b=temp; } int main() { int a,b; a=0;b=1; swap(a,b); cout<<a<<"\n"<<b<<endl; }
做用:可讓函數的調用做爲左值。
示例:
//建立一個函數 int& num(){ static int a=10; //建立靜態變量,儲存在全局區中 return a; } int main() { int& ref=num(); // 給num函數中的a搞一個引用 num()=1000; cout<<ref<<endl; //驗證將函數調用做爲左值是否有效 return 0; }
做用:能夠用來修飾形參,防止實參被影響。
示例:
void change(const int& a){ //使用const修飾形參 //此處不可修改a的值 cout<<a; } int main() { int a=1; change(a); return 0; }
C++面向對象的三大特性:封裝、繼承、多態。
萬物皆對象、對象上有其屬性和行爲。
封裝是c++面向對象三大特徵之一
封裝的意義:
示例:
#include <iostream> using namespace std; #define Pi 3.1415926 //定義一個宏常量Pi class circle{ //建立一個circle類 public: //定義公有部分 int r; //定義一個半徑屬性r double circle_C(){ //定義一個成員函數,計算周長 return 2*r*Pi; } void set_r(double set_r){ r=set_r; } }; int main() { circle yuan; //經過circle類實例化一個對象 yuan.r=10; //給對象的公有屬性r賦值 cout << yuan.circle_C() << endl; //經過成員函數輸出周長 yuan.set_r(5); cout << yuan.circle_C() << endl; //經過成員函數輸出周長驗證修改 return 0; }
總共有三個權限
名稱 | 意義 | 特色 |
---|---|---|
public | 公共權限 | 類內和類外均可以訪問 |
protected | 保護權限 | 類內能夠訪問,類外不能夠訪問,子能夠訪問父的保護內容 |
private | 私有權限 | 類內能夠訪問,類外不能夠訪問,子不可訪問父的私有內容 |
class
和struct
的區別:
class
默認是私有權限,struct
默認是公有權限。優勢:
示例:
#include <iostream> using namespace std; class human{ public: void setName(string set_name){ //定義一個用來設置姓名的成員函數 name=set_name; } string getName(){ //定義一個獲取姓名的成員函數 return name; } void setAge(int set_age){ //定義一個用來設置年齡的成員函數 if (set_age<0 || set_age>150){ //使用if語句判斷所給值是否合法 cout<<"非法數據!"; }else{ age=set_age; } } int getAge(){ //定義一個用來獲取年齡的成員函數 return age; } void setLover(string set_lover){ //定義一個用來設置愛人的成員函數 lover=set_lover; } private: //私有屬性的定義 string name; int age; string lover; }; int main() { human maicss; //實例化一個對象 //使用成員函數設置相關屬性 maicss.setName("Maicss"); maicss.setAge(18); maicss.setLover("qian"); //使用成員函數獲取相關私有函數的值在 cout<<"name:"<<maicss.getName()<<" age:"<<maicss.getAge()<<endl; return 0; }
對象的初始化
和清理
是兩個重要的問題。
注意:
空實現
。做用:
語法:
構造函數:類名(){}
析構函數:~類名(){}
~
。delete
語句。示例:
class human{ public: //爲了保證構造函數和析構函數能被全局調用,因此須要設置爲public權限 human(){ //建立一個構造函數 cout<<"human的構造函數被調用\n"; } ~human(){ //建立一個析構函數 cout<<"human的析構函數被調用\n"; } }; void hum(){ //函數中實例化一個對象,函數運行結束後對象被銷燬 human m; } int main() { human maicss;//建立對象同時運行構造函數 hum(); //調用hum函數來建立對象,同時運行構造函數 //hum函數運行結束時對象m被銷燬,同時運行析構函數 return 0;//mian函數返回0,程序結束前會運行析構函數 }
兩種分類方式:
三種調用方式:
注意事項:
()
,不然會被認爲是函數定義。示例(有點長):
class human{ public: human(){ cout<<"human的無參(默認)構造函數被調用\n"; } human(int a){ age=a; cout<<"human的有參構造函數被調用\n"; } human(const human &p){ //const的意義是不容許在構造函數中修改傳入對象的屬性,只讀。 age=p.age; cout<<"human的拷貝構造函數被調用\n"; } ~human(){ cout<<"human的析構函數被調用\n"; } int age; }; void hum1(){ //括號法調用 human m1; //無參構造 human m2(10); //有參構造 human m3(m1); //拷貝構造 } void hum2(){ //顯示法 human m1; //無參構造 human m2=human(10); //有參構造 human m3=human(m1); //拷貝構造 } void hum3(){ //隱式轉換法 human m1; //無參構造 human m2=10; //有參構造 human m3=m2; //拷貝構造 } int main() { hum1(); hum2(); hum3(); return 0; }
C++中拷貝構造函數的調用時機一般由三種狀況:
默認狀況下,C++編譯器至少給一個類添加三個函數:
構造函數調用規則:
定義:
注意:
示例(淺拷貝):
class person{ public: person(){ cout<<"無參構造函數被調用\n"; } person(int age,int height){ m_height=new int (height); //在堆區申請一塊內存區域用來存放height m_age=age; cout<<"有參構造函數被調用\n"; } ~person(){ if(m_height!=NULL){ delete m_height; //釋放m_height指向的內存區域 //析構函數會被執行兩次,由於兩個對象在man()函數結束後被銷燬,可是因爲淺拷貝將指針拷貝給第二個對象,所以兩個對象的m_height指針指向了堆區的同一塊內存區域,這塊內存區域釋放兩次,會報錯。 m_height=NULL; //將指針指向NULL,防止野指針的出現。 } cout<<"析構函數被調用\n"; } private: int m_age; int * m_height; //建立一個int指針指向有參構造申請的內存區域 }; void man(){ person one(16,160); person two(one);//淺拷貝 } int main() { man(); cout << "Hello World!" << endl; return 0; }
示例(深拷貝):
class person{ public: person(){ cout<<"無參構造函數被調用\n"; } person(int age,int height){ m_height=new int (height); //在堆區申請一塊內存區域用來存放height m_age=age; cout<<"有參構造函數被調用\n"; } person(const person &p){ m_age=p.m_age; m_height=new int (*p.m_height);//在堆區從新申請一塊內存實現深拷貝 } ~person(){ if(m_height!=NULL){ delete m_height; //釋放m_height指向的內存,此時不會出現屢次釋放同一內存空間的問題 m_height=NULL; //將指針指向NULL,防止野指針的出現。 } cout<<"析構函數被調用\n"; } int m_age; int * m_height; //建立一個int指針指向有參構造申請的內存區域 }; void man(){ person one(16,160); person two(one);//因爲定義了拷貝函數,因此此處會經過定義實現深拷貝 cout<<one.m_age<<" "<<*one.m_height<<endl; cout<<two.m_age<<" "<<*two.m_height<<endl; } int main() { man(); cout << "Hello World!" << endl; return 0; }
做用:初始化列表語法能夠用來初始化對象屬性。
語法:構造函數():屬性1(值1),屬性2(值2), ...
示例:
class person{ public: person(int a,int b):age(a),height(b){} int age; int height; }; void man(){ person one(18,180); cout<<"age:"<<one.age<<" height:"<<one.height<<endl; } int main() { man(); return 0; }
定義:一個類聲明的對象成爲另外一個類的屬性成員。
例如:
class A{} class B{ A a; }
注意:
靜態成員能夠看做屬於類的做用域,被全部對象公用。
靜態成員變量和靜態成員函數都有權限控制。
靜態成員變量
做用:全部成員公用一個成員變量。
語法:static 數據類型 變量名
注意:
示例:
class human{ public: static int age;//在類內的聲明 }; int human::age=100;//在類外的初始化 int main() { human a; cout<<a.age<<endl; human b; b.age=18;//使用對象b給靜態變量從新賦值 //也能夠經過類名操做成員變量 human::age=18; cout<<a.age<<endl;//此時對象a的age值也會隨b變成18 return 0; }
靜態成員函數
做用:全部成員公用一個成員函數。屬於類的做用域。
語法:static 函數返回值類型 函數名();
注意:靜態成員函數屬於類的做用域,只能操做靜態成員變量。
示例:
class human{ public: static void func(){ age=1; } static int age;//在類內的聲明 }; int human::age=100;//在類外的初始化 int main() { human a; cout<<a.age<<endl; human b; //訪問靜態成員函數,下面兩種方式效果徹底相同 b.func();//經過對象訪問 human::func();//經過類的做用域訪問 cout<<a.age<<endl; return 0; }
做用:this指針指向被調用的成員函數所屬的對象。
特色:
使用場景:
return *this
。示例:
class human{ public: void c_age(int age){ this->age=age;//用this指針表示成員變量 } human& addage(human &p){ //函數返回值要用引用的方式返回,不然會建立新對象 this->age+=p.age; return *this; } int age; }; void func(){ human maicss; human p1; p1.age=10; maicss.c_age(18); maicss.addage(p1).addage(p1).addage(p1); //鏈式編程思想 cout<<"maicss的年齡是:"<<maicss.age<<endl; } int main() { func(); return 0; }
空指針能夠調用成員,可是爲了防止崩潰,要避免訪問成員變量。
class human{ public: void printname(){ cout<<"name is maicss\n"; } void printage(){ if (this==NULL){//防止程序崩潰進行的保險措施 return ; } cout<<"age is "<<this->age<<endl; } int age; }; void func(){ human * maicss=NULL; maicss->printname();//使用空指針訪問成員函數 maicss->printage();//使用空指針在成員函數中訪問成員變量 } int main() { func(); return 0; }
常函數:
const
,咱們稱這個函數爲常函數。mutable
後,在常函數中依然能夠修改。常對象:
const
稱該對象爲常對象。示例:
class human{ public: human(){}//新建一個無參構造函數,爲了建立常對象 void func() const{ //age=18; //因爲成員函數末尾加了const,因此函數體內不容許修改爲員變量 height=180; //因爲成員變量前加了mutable關鍵字,因此該變量能夠在函數中修改 } void func2(){} int age; mutable int height; }; int main() { human maicss; const human maicss2; //maicss2.func2(); //因爲是常對象,因此只能調用常函數。也只能修改帶有mutable關鍵字的成員變量 maicss.func(); return 0; }
做用:讓一個函數或類,訪問另外一個類中的私有成員。
關鍵字:friend
三種實現方式:
示例:
class room; //聲明類 class goodgay2{ public: goodgay2(); void visit(); room * m_room; //建立一個指針 }; class goodgay{ public: goodgay(); //聲明構造函數 void visit(); //聲明成員函數用於訪問room的私有成員 room * m_room; //建立一個指針 }; class room{ friend void text(); //將全局函數做爲友元 friend class goodgay; //將另外一個類做爲友元 friend void goodgay2::visit(); public: string sittingroom="客廳"; private: string bedroom="臥室"; }; goodgay::goodgay(){ //類外定義構造函數 m_room=new room; //在構造函數中於堆區建立一個對象 } goodgay2::goodgay2(){ m_room=new room; } void goodgay::visit(){ //類外定義成員函數 cout<<"b在訪問:"<<m_room->bedroom<<endl; cout<<"b在訪問:"<<m_room->sittingroom<<endl;//訪問room的私有成員 }; void goodgay2::visit(){ cout<<"c在訪問:"<<m_room->bedroom<<endl;//訪問room的私有成員 } void text(){ room a; cout<<"a訪問了:"<<a.bedroom<<endl; goodgay b; b.visit(); //經過訪問visit成員函數訪問room的私有成員 goodgay2 c; c.visit(); } int main() { text(); return 0; }
方式:
示例:
//使用成員函數重載 class Person{ public: int age; int height; public: Person operator+(Person &p); //使用成員函數對加號的重載 }; Person Person::operator+(Person &p){//定義重載函數 Person temp; temp.age=this->age+p.age; temp.height=this->height+p.height; return temp; } int main(){ Person p1; Person p2; p1.age=10; p2.age=18; p1.height=159; p2.height=180; Person p3=p1+p2; cout<<"P3的年齡爲:"<<p3.age<<" P3的身高爲:"<<p3.height<<endl; return 0; }
//使用全局函數重載 class Person{ public: int age; int height; }; Person operator+(Person &p1,Person &p2){ //使用成員函數對加號的重載 Person temp; temp.age=p1.age+p2.age; temp.height=p1.height+p2.height; return temp; } int main(){ Person p1; Person p2; p1.age=10; p2.age=18; p1.height=159; p2.height=180; Person p3=p1+p2; cout<<"P3的年齡爲:"<<p3.age<<" P3的身高爲:"<<p3.height<<endl; return 0; }
繼承使面向對象三大特性之一
定義某些了類時,下一級別的成員擁有上一級別的共性,還有本身的特性。
使用繼承能夠儘可能減小代碼
用法:class A : public B;
說明:上述A爲子類(派生類),B爲父類(基類)。
示例:
class base{ //建立一個基類 public: int age; string name; }; class human : public base{ //建立一個以base爲基類的派生類 public: int score; }; class dog : public base{//另外一個以base爲基類的派生類 public: human master; }; void test1(){ //對派生類中屬性的訪問示例 human maicss; dog dazhuang; dazhuang.age=4; maicss.age=20; dazhuang.name="DAZ"; maicss.name="Maicss"; dazhuang.master=maicss; maicss.score=100; } int main() { void test1(); return 0; }
注意:
(這是依我本身理解的)
protected
的成員變量爲保護權限,此時子類能夠訪問這種成員變量,可是若是是private
則沒法訪問,這也是二者的惟一區別。使用文件操做須要包含頭文件<fstream>
文件類型分爲兩種:
操做文件三大類:
ofstream
寫文件ifstream
讀文件fstream
讀寫文件寫文件的基本步驟:
//1.包含頭文件 #include <fstream> //2.建立流對象 ofstream ofs; //3.打開文件 ofs.open("文件路徑",打開方式); //4.寫數據 ofs<<"文本文件"; //5.關閉文件 ofs.close();
打開方式 | 解釋 |
---|---|
ios::in | 爲讀文件而打開文件 |
ios::out | 爲寫文件而打開文件 |
ios::ate | 初始位置:文件尾 |
ios::app | 追加方式寫文件 |
ios::trunc | 若是文件存在,先刪除再建立 |
ios::binary | 二進制方式 |
文件打開方式配合使用須要|
符號
示例:
#include <iostream> #include <fstream> //包含文件流頭文件 using namespace std; int main() { std::ofstream ofs; //建立一個ofstream類對象,實現寫文件 ofs.open("text.txt",ios::out); //打開文件 ofs<<"你好世界"; //寫到文件 return 0; }
寫文件的基本步驟:
//包含頭文件 #include <fstream> //建立流對象 std::ifstream ifs; //打開文件 ifs.open("文件路徑",打開方式); if (!ifs.is_open()){ cout<<"文件打開失敗"<<endl; return ; } //讀入文件 //第一種方式 char text1[1024]={0}; while (ifs>>text1) { cout<<text1<<endl; } //第二種方式 char text2[1024]={0}; while (ifs.getline(text2,sizeof(text2))){ cout<<text2<<endl; } //第三種方式 string text3; while (getline(ifs,text3)) { cout<<text3<<endl; } //第四種方式 char text4; while ((text4=ifs.get())!=EOF){ cout<<text4; } //關閉文件 close
STL是爲了提升軟件代碼的複用性而產生的一種標準模板庫
容器:vector
算法:for_each
迭代器:vector<int>::iterator
示例:
#include <iostream> using namespace std; #include <vector>//使用容器必須引入頭文件 void print(int i) {//第三種遍歷方法要用到 cout << i << endl; } int main() { vector<int> v; v.push_back(1);//使用尾插添加元素 v.push_back(2); v.push_back(3); v.push_back(4); //遍歷容器的第一種方法 vector<int>::iterator head = v.begin();//begin()會返回指向容器中第一個元素的指針 vector<int>::iterator tail = v.end();//end()會返回指向容器中最後一個元素的下一個位置的指針 while (head != tail) { cout << *head << endl; head++; } //遍歷容器的第二種方法(是第一種方式的簡化) for (vector<int>::iterator h = v.begin(); h != v.end(); h++) { cout << *h << endl; } //遍歷容器的第三種方法(使用標準算法庫中的for_each) for_each(v.begin(),v.end(),print); getchar(); return 0; }
string
和char *
的區別
string();
無參構造,建立一個空的字符串。string(const char* s);
使用字符串s進行初始化。string(const string& str);
使用字符串str初始化。string(int n,char c);
使用n個字符c初始化。rand()%10
能夠生成0~9的隨機數。srand((unsigned int)time(NULL))
(須要#include <ctime>
)獲取內存地址
注意:
static
爲靜態變量。