C++--day06
目錄:?
1. C的提高 1-131P 時間七天?
2. C++的基礎 132-286P 時間八天?
3. C++的提高 287-378P 時間五天?
4. C/C++的數據結構 379-482P 時間五天?
5. C/C++的設計模式基礎 483-540P 時間三天
?
視頻資料:https://www.bilibili.com/video/av27904891?from=search&seid=10891514449061956870
?
P179??copy構造函數調用時機4-函數返回值是匿名對象
#include<iostream> using namespace std;class Location { public:Location( int xx = 0 , int yy = 0 ) { X = xx ; Y = yy ; cout << "Constructor Object.\n"<<endl ; }Location( const Location & p ) //拷貝構造函數 完成對象的初始化 { X = p.X ; Y = p.Y ; cout << "Copy_constructor called." << endl ; }~Location() { cout << X << "," << Y << " Object destroyed." << endl ; }int GetX () { return X ;} int GetY () { return Y ;} private : int X , Y ; } ;//g函數返回一個元素
//結論:函數的返回值是一個元素(復雜類型),返回的是一個新的匿名對象? 所以會調用匿名對象類的拷貝對象函數
?輸出結果
?
P180??copy構造函數調用時機3-函數返回值是匿名對象去和留的剖析
#include<iostream> using namespace std;class Location { public:Location( int xx = 0 , int yy = 0 ) { X = xx ; Y = yy ; cout << "Constructor Object.\n"<<endl ; }Location( const Location & p ) //拷貝構造函數 完成對象的初始化 { X = p.X ; Y = p.Y ; cout << "Copy_constructor called." << endl ; }~Location() { cout << X << "," << Y << " Object destroyed." << endl ; }int GetX () { return X ;} int GetY () { return Y ;} private : int X , Y ; } ; //g函數返回一個元素 //結論1:函數的返回值是一個元素(復雜類型),返回的是一個新的匿名對象(所以會調用匿名對象類的拷貝對象函數) //結論2:有關匿名對象的去和留 // 如果用匿名對象初始化另外一個同類型的對象,匿名匿名對象,轉成有名對象 // 如果用匿名對象賦值給另外一個同類型的對象,匿名對象被析構//這么寫代碼,編譯器返回一個新對象(沒有名字的匿名對象) Location g() {Location A(1,2);return A; } // void objplay1() {g();} void objplay2() {//用匿名對象初始化m,此時C++編譯器直接把匿名對象轉成m;從匿名轉成有名字了Location m=g();printf("匿名對象被扶正,不會被析構\n");cout<<m.GetX()<<endl;} void objplay3() {//用匿名對象賦值給m2,匿名對象會析構Location m2(1,2);m2=g();printf("因為用匿名對象=給m2,匿名對象被析構\n");cout<<m2.GetX()<<endl;} void main() {objplay3();system("pause"); }?
P181? 構造和析構的重點整理
?
?
P183? 構造和析構的總結
1、 構造函數的基礎
2、 構造函數的分類
有參構造函數
無參構造函數
賦值構造函數
默認構造函數
?3、拷貝函數的調用時機
?4、C++編譯器提供的構造函數 PK 對象顯示初始化方案
?5、拷貝構造函數
?6、構造函數調用規則研究
? ? ? ?若定義構造函數,則必須調用
若不定義構造函數 使用C++編譯提供的構造函數
?7、深拷貝和淺拷貝
?8、構造函數初始化列表
對象互組
?9、構造和析構的調用順序研究
先調用成員變量的構造函數,再調用自己的構造函數
#include <iostream> using namespace std;void objplaymain71();class Test { public:Test(){a = 0; b = 0;cout << "無參數構造函數 自動被調用" <<endl;}Test(int _a) //有參數構造函數 {a = _a;b = 0;}Test(const Test& obj) //copy構造函數 作用: 用一個對象初始化另外一個對象 {a = obj.a + 100;b = obj.b + 100;}void printT(){cout << "a:" << a << "b: "<<b<< endl; }~Test(){cout<<"我是析構函數 對象生命周期結束時,會被c++編譯器自動調用" <<endl;}protected: private:int a;int b; };// 第3種調用時機 void printTest(Test t) {; }// 1 和 2 void objplaymain72() {// Test t1(1); //ok Test t2(t1); Test t3 = t1; //會調用copy構造函數 printTest(t3); }//copy構造函數的第4種調用時機 //返回一個元素 匿名對象 Test getTestObj() {Test t(1);return t; }void TestNoNameObj() {Test myt1 =getTestObj(); //用匿名對象初始化 另外一個對象 Test myt2(1);myt2 = getTestObj(); //用匿名對象 給 另外一個對象 賦值 匿名對象被析構 }int main() {//objplaymain(); objplaymain72();TestNoNameObj();cout<<"hello..."<<endl;system("pause");return 0; }void objplaymain71() {Test t1; //ok//Test t2() ; //調用無參數構造函數的 錯誤方法//t2.printT();// Test t3(1); //c++編譯器自動的調用構造函數Test t4 = 4; //c++編譯器自動的調用構造函數Test t5 = Test(5); //程序員手工的調用構造函數// Test t6 = t1;return ; }?
P184? 構造函數的調用規則研究
默認構造函數
二個特殊的構造函數
1)默認無參構造函數
當類中沒有定義構造函數時,編譯器默認提供一個無參構造函數,并且其函數體為空
2)默認拷貝構造函數
當類中沒有定義拷貝構造函數時,編譯器默認提供一個默認拷貝構造函數,簡單的進行成員變量的值復制
?
?
構造函數調用規則研究
1)當類中沒有定義任何一個構造函數時,c++編譯器會提供默認無參構造函數和默認拷貝構造函數
2)當類中定義了拷貝構造函數時,c++編譯器不會提供無參數構造函數
3) 當類中定義了任意的非拷貝構造函數(即:當類中提供了有參構造函數或無參構造函數),c++編譯器不會提供默認無參構造函數
4 )默認拷貝構造函數成員變量簡單賦值
總結:只要你寫了構造函數,那么你必須用。
?
#include <iostream> using namespace std;class Test { public:// Test(const Test& obj) //copy構造函數 作用: 用一個對象初始化另外一個對象 // { // a = obj.a + 100; // b = obj.b + 100; // }// Test(int _a, int _b) // { // ; // } Test(){cout<<"hi"<<endl;}void printT(){cout << "a:" << a << "b: "<<b<< endl; }private:int a;int b; };//當類中定義了拷貝構造函數時,c++編譯器不會提供無參數構造函數 //當類中定義了有參數構造函數是,c++編譯器不會提供無參數構造函數//在定義類時, 只要你寫了構造函數,則必須要用int main() {Test t1; //調用無參構造函數cout<<"hello..."<<endl;system("pause");return 0; }?
P187? 深淺拷貝問題
#define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std;class Name { public:Name (const char *myp){m_len=strlen(myp);m_p=(char *)malloc(m_len+1);// strcpy(m_p,myp);}//解決方案:手工的編寫拷貝構造函數 使用深copyName(const Name& obj1){m_len=obj1.m_len;m_p=(char *)malloc(m_len+1);strcpy(m_p,obj1.m_p);}~Name(){if (m_p!=NULL){free(m_p);m_p=NULL;m_len=0;}} private:char *m_p;int m_len; };void objpalymain() {Name obj1("abcde");Name obj2=obj1;//默認的拷貝構造函數 C++編譯器提供的 }void main() {objpalymain();system("pause"); }?
?
?P188? 深拷貝和淺拷貝-默認的等號操作符也是淺拷貝
#define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std;class Name { public:Name (const char *myp){m_len=strlen(myp);m_p=(char *)malloc(m_len+1);// strcpy(m_p,myp);}//解決方案:手工的編寫拷貝構造函數 使用深copyName(const Name& obj1){m_len=obj1.m_len;m_p=(char *)malloc(m_len+1);strcpy(m_p,obj1.m_p);}~Name(){if (m_p!=NULL){free(m_p);m_p=NULL;m_len=0;}} private:char *m_p;int m_len; };void objpalymain() {Name obj1("abcde");//Name obj2=obj1;//默認的拷貝構造函數 C++編譯器提供的 Name obj3("obj3");obj3 = obj1;//等號操作 }void main() {objpalymain();system("pause"); }?
?
?
P189? 構造函數的初始化列表
1、對象初始化列表 ?
1)對象初始化列表出現原因
1.必須這樣做:
如果我們有一個類成員,它本身是一個類或者是一個結構,而且這個成員它只有一個帶參數的構造函數,沒有默認構造函數。這時要對這個類成員進行初始化,就必須調用這個類成員的帶參數的構造函數,
如果沒有初始化列表,那么他將無法完成第一步,就會報錯。
?
2.類成員中若有const修飾,必須在對象初始化的時候,給const int m 賦值
當類成員中含有一個const對象時,或者是一個引用時,他們也必須要通過成員初始化列表進行初始化,
因為這兩種對象要在聲明后馬上初始化,而在構造函數中,做的是對他們的賦值,這樣是不被允許的。
2)C++中提供初始化列表對成員變量進行初始化
語法規則
Constructor::Contructor() : m1(v1), m2(v1,v2), m3(v3)
{
??? ?// some other assignment operation
}
3)注意概念
初始化:被初始化的對象正在創建
賦值:被賦值的對象已經存在
?
4)注意:
成員變量的初始化順序與聲明的順序相關,與在初始化列表中的順序無關
初始化列表先于構造函數的函數體執行
?#include<iostream>
using namespace std;class A { public:A(int _a){a=_a;cout<<"構造函數"<<"a:"<<a<<endl;}~A(){cout<<"A的析構函數"<<"a:"<<a<<endl;} protected: private:int a; }; //1 構造函數的初始化列表 解決: 在B類中 組合了一個 A類對象 (A類設計了構造函數) // 根據構造函數的調用規則 設計A的構造函數, 必須要用;沒有機會初始化A // 新的語法 Constructor::Contructor() : m1(v1), m2(v1,v2), m3(v3) class B { public:B(int _b1,int _b2):a1(1),a2(2),c(0){b1=_b1;b2=_b2;}B(int _b1,int _b2,int m,int n):a1(m),a2(n),c(0){b1=_b1;b2=_b2;cout<<"B的構造函數"<<endl;}~B(){cout<<"B的析構函數"<<endl;} protected: private:int b1;int b2;A a1;A a2;const int c;
};//2 先執行 被組合對象的構造函數 // 如果組合對象有多個,按照定義順序, 而不是按照初始化列表的順序// 析構函數 : 和構造函數的調用順序相反//3 被組合對象的構造順序 與定義順序有關系 ,與初始化列表的順序沒有關系 //4 初始化列表 用來 給const 屬性賦值 void obj10play() {//A a1(10);//1. 參數傳遞B objB(1,2,3,4);//2. 調用順序 } void main() {obj10play();system("pause"); }
?
輸出結果
?
P190? 強化訓練1--構造和析構調用順序
//對象做函數參數 //1 研究拷貝構造 //2 研究構造函數,析構函數的調用順序//總結 構造和析構的調用順序 #include "iostream" using namespace std;class ABCD { public:ABCD(int a, int b, int c){this->a = a;this->b = b;this->c = c;printf("ABCD() construct, a:%d,b:%d,c:%d \n", this->a, this->b, this->c);}~ABCD(){printf("~ABCD() construct,a:%d,b:%d,c:%d \n", this->a, this->b, this->c);}int getA() {return this->a;} private:int a;int b;int c; };class MyE { public:MyE():abcd1(1,2,3),abcd2(4,5,6),m(100){cout<<"MyD()"<<endl;}~MyE(){cout<<"~MyD()"<<endl;}MyE(const MyE & obj):abcd1(7,8,9),abcd2(10,11,12),m(100){printf("MyD(const MyD & obj)\n");}protected://private: public:ABCD abcd1; //c++編譯器不知道如何構造abc1 ABCD abcd2;const int m;};int doThing(MyE mye1)//是一個元素,用實參初始化形參,調用形參拷貝構造函數 {printf("doThing() mye1.abc1.a:%d \n", mye1.abcd1.getA()); return 0; }int run2() {MyE myE;doThing(myE);//實參調用doThing函數return 0; }// int run3() {printf("run3 start..\n");//ABCD(400, 500, 600); //臨時對象的生命周期 ABCD abcd = ABCD(100, 200, 300);//若直接調用構造函數呢?//想調用構造函數對abc對象進行再復制,可以嗎?//在構造函數里面調用另外一個構造函數,會有什么結果? printf("run3 end\n");return 0; }int main() {run2();//run3();system("pause");return 0; }輸出結果
?
P191? ?強化訓練2--匿名對象聲明周期
//研究構造函數,析構函數的調用順序 //總結 構造和析構的調用順序 #include "iostream" using namespace std;class ABCD { public:ABCD(int a, int b, int c){this->a = a;this->b = b;this->c = c;printf("ABCD() construct, a:%d,b:%d,c:%d \n", this->a, this->b, this->c);}~ABCD(){printf("~ABCD() construct,a:%d,b:%d,c:%d \n", this->a, this->b, this->c);}int getA() {return this->a;} private:int a;int b;int c; }; int run3() {printf("run3 start..\n");//ABCD(400, 500, 600); //臨時對象的生命周期 ABCD abcd = ABCD(100, 200, 300);//若直接調用構造函數呢?//想調用構造函數對abc對象進行再復制,可以嗎?//在構造函數里面調用另外一個構造函數,會有什么結果? printf("run3 end\n");return 0; }int main() { run3();system("pause");return 0; }?
第一種?ABCD(400, 500, 600)輸出結果 -- 先調用構造函數然后緊接著調用析構函數:因為是匿名對象,沒有人接管它
第二種?ABCD abcd = ABCD(100, 200, 300);輸出結果 -- 匿名對象轉正abcd,運行完畢之后會調用析構函數
?
?
?P192??強化訓練3--構造中調用構造(產生匿名對象)
#include "iostream" using namespace std;//構造中調用構造是危險的行為 class MyTest { public:MyTest(int a, int b, int c){this->a = a;this->b = b;this->c = c;}MyTest(int a, int b){this->a = a;this->b = b;MyTest(a, b, 100); //產生新的匿名對象 }~MyTest(){printf("MyTest~:%d, %d, %d\n", a, b, c);}protected: private:int a;int b;int c;public:int getC() const{return c; }void setC(int val) {c = val;} };int main() {MyTest t1(1, 2);printf("c:%d\n", t1.getC()); //請問c的值是?system("pause");return 0; }?
?輸出結果:
?
由上節可知,匿名對象的生命周期先調用構造函數然后緊接著調用析構函數:因為是匿名對象,沒有人接管它
匿名對象和t1沒有關系,調用的是匿名對象的析構函數
?
?
P193? new和delete的基本語法
1)在軟件開發過程中,常常需要動態地分配和撤銷內存空間,例如對動態鏈表中結點的插入與刪除。在C語言中是利用庫函數malloc和free來分配和撤銷內存空間的。
? C++提供了較簡便而功能較強的運算符new和delete來取代malloc和free函數。
? ? ?注意: new和delete是運算符,不是函數,因此執行效率高。
?
2)雖然為了與C語言兼容,C++仍保留malloc和free函數,但建議用戶不用malloc和free函數,而用new和delete運算符。
new運算符的例子:
new int; //開辟一個存放整數的存儲空間,返回一個指向該存儲空間的地址(即指針) new int(100); //開辟一個存放整數的空間,并指定該整數的初值為100,返回一個指向該存儲空間的地址 new char[10]; //開辟一個存放字符數組(包括10個元素)的空間,返回首元素的地址 new int[5][4]; //開辟一個存放二維整型數組(大小為5*4)的空間,返回首元素的地址 float *p=new float (3.14159); //開辟一個存放單精度數的空間,并指定該實數的初值為//3.14159,將返回的該空間的地址賦給指針變量p
3)new和delete運算符使用的一般格式為:
?
用new分配數組空間時不能指定初值。如果由于內存不足等原因而無法正常分配空間,則new會返回一個空指針NULL,用戶可以根據該指針的值判斷分配空間是否成功。
4)?應用舉例
?
////分配基礎類型 void main() {// int *p = (int *)malloc(sizeof(int));*p = 10;free(p);int *p2 = new int; //分配基礎類型*p2 = 20;free(p2);// int *p3 = new int(30);printf("*p3:%d \n", *p3);//30delete p3;cout<<"hello..."<<endl;system("pause");return ; }?
?
//分配數組變量 void main() {//c語言分配數組int *p = (int *)malloc(sizeof(int) * 10); //int array[10];p[0] = 1;free(p);//c++分配數組 int *pArray = new int[10] ;pArray[1] = 2;delete [] pArray; //數組不要把[] 忘記char *pArray2 = new char[25] ; //char buf[25]delete [] pArray2;cout<<"hello..."<<endl;system("pause");return ; }?
?
class Test { public:Test(int _a){a = _a;cout<<"構造函數執行" <<endl;}~Test(){cout<<"析構函數執行" <<endl;}protected: private:int a; };//分配對象new delete //相同 和 不同的地方 new能執行類型構造函數 delete操作符 能執行類的析構函數 void main() {//c Test *pT1 = (Test *)malloc(sizeof(Test));free(pT1);//c++Test *pT2 = new Test(10);delete pT2;cout<<"hello..."<<endl;system("pause"); }?
P194? ?new和delete深入分析
混用測試、異同比較
結論:? ?malloc不會調用類的構造函數
Free不會調用類的析構函數
#include <iostream> using namespace std;// 1 // malloc free c語言的函數 // new delete 操作符 c++的語法//2 new 基礎類型變量 分配數組變量 分配類對象//3 ////分配基礎類型--混搭沒有問題 void main01() {// int *p = (int *)malloc(sizeof(int));*p = 10;//free(p);delete p;int *p2 = new int; //分配基礎類型*p2 = 20;free(p2);// int *p3 = new int(30);printf("*p3:%d \n", *p3);//delete p3;free(p3);cout<<"hello..."<<endl;system("pause");return ; }//分配數組變量 void main02() {//c語言分配數組int *p = (int *)malloc(sizeof(int) * 10); //int array[10];p[0] = 1;//free(p);delete[] p;//c++分配數組 int *pArray = new int[10] ;pArray[1] = 2;//delete [] pArray; //數組不要把[] 忘記free(pArray);char *pArray2 = new char[25] ; //char buf[25]delete [] pArray2;cout<<"hello..."<<endl;system("pause");return ; }class Test { public:Test(int _a){a = _a;cout<<"構造函數執行" <<endl;}~Test(){cout<<"析構函數執行" <<endl;}protected: private:int a; };//分配對象new delete //相同 和 不同的地方 new能執行類型構造函數 delete操作符 能執行類的析構函數// malloc free 函數 C 只會分配內存大小 不會調用類的構造析構函數 // new delete 操作符號 c++的關鍵字 //結論 void main() {//c Test *pT1 = (Test *)malloc(sizeof(Test));//free(pT1);delete pT1;//c++Test *pT2 = new Test(10);//delete pT2;free(pT2);cout<<"hello..."<<endl;system("pause"); }?
P195? 靜態成員變量和靜態成員函數
1)定義靜態成員變量
- 關鍵字 static?可以用于說明一個類的成員,
? ? ? ? ? ?靜態成員提供了一個同類對象的共享機制
- 把一個類的成員說明為 static?時,這個類無論有多少個對象被創建,這些對象共享這個 static?成員
- 靜態成員局部于類,它不是對象成員
2)靜態成員函數
1)概念
- 靜態成員函數數冠以關鍵字static
- 靜態成員函數提供不依賴于類數據結構的共同操作,它沒有this指針
- 在類外調用靜態成員函數用 “類名?::?”作限定詞,或通過對象調用
2)案例?
#include<iostream> using namespace std;class BB { public:void printC(){cout<<"c:"<<c<<endl;}void AddC(){c=c+1; //成員函數訪問靜態數據成員 }static void getC() //靜態成員函數 {cout<<"c:"<<c<<endl;//請在靜態成員函數中,能調用 普通成員屬性 或者 普通成員函數嗎?cout<<"a:"<<a<<endl; //error C2597: 對非靜態成員“BB::a”的非法引用 } private:int a;int b;static int c;//聲明與定義靜態數據成員 };int BB::c=10;//聲明與定義靜態數據成員void main() {BB b1,b2,b3;b1.printC();//10b2.AddC();//11b3.printC();//11//靜態成員函數調用的方法b3.getC();//用對象 BB::getC();system("pause");//類:: }?
?
?static中取a的值,不確定是哪個對象的a,對非靜態成員“BB::a”的非法引用
?static中取c的值c,c是個靜態成員,靜態成員是屬于整個類的
在靜態成員函數中只能使用靜態成員變量,不能使用普通成員函數
?
** C++編譯器是如何支持面向對象的機制的
?
P196? C++面向對象模型初探
基礎知識
C++中的class從面向對象理論出發,將變量(屬性)和函數(方法)集中定義在一起,用于描述現實世界中的類。從計算機的角度,程序依然由數據段和代碼段構成。
C++編譯器如何完成面向對象理論到計算機程序的轉化?
換句話:C++編譯器是如何管理類、對象、類和對象之間的關系
具體的說:具體對象調用類中的方法,那c++編譯器是如何區分,是那個具體的類,調用這個方法那?
#include "iostream"using namespace std;class C1 { public:int i; //4int j; //4int k; //4 protected: private: }; //12class C2 { public:int i; int j; int k; static int m; //4 public:int getK() const { return k; } //4void setK(int val) { k = val; } //4protected: private: }; //24 16 12(鐵釘的不對)struct S1 {int i;int j;int k; }; //12struct S2 {int i;int j;int k;static int m; }; //16int main() {printf("c1:%d \n", sizeof(C1));//12printf("c2:%d \n", sizeof(C2));//12printf("s1:%d \n", sizeof(S1));//12printf("s2:%d \n", sizeof(S2));//12 system("pause"); }?
1)C++類對象中的成員變量和成員函數是分開存儲的
成員變量:
普通成員變量:存儲于對象中,與struct變量有相同的內存布局和字節對齊方式
靜態成員變量:存儲于全局數據區中
成員函數:存儲于代碼段中。
問題出來了:很多對象共用一塊代碼?代碼是如何區分具體對象的那?
換句話說:int getK() const { return k; },代碼是如何區分,具體obj1、obj2、obj3對象的k值?
1、C++類對象中的成員變量和成員函數是分開存儲的。C語言中的內存四區模型仍然有效!
2、C++中類的普通成員函數都隱式包含一個指向當前對象的this指針。
3、靜態成員函數、成員變量屬于類
靜態成員函數與普通成員函數的區別
靜態成員函數不包含指向具體對象的指針
普通成員函數包含一個指向具體對象的指針
?
?P197? this指針
#include <iostream> using namespace std;class Test { public:Test(int a, int b) //---> Test(Test *this, int a, int b) {this->a = a;//this就是t1取地址,誰調用它它就是誰this->b = b; }void printT(){cout<<"a: " <<a <<endl;cout<< "b: " << this->b <<endl;} protected: private:int a;int b; };void main() {Test t1(1, 2);t1.printT();// ===> printT(&t1)cout<<"hello..."<<endl;system("pause");return ; }?
?
轉載于:https://www.cnblogs.com/yangyuqing/p/10408219.html
總結
以上是生活随笔為你收集整理的C++--day06的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微服务实战:从架构到发布(二)
- 下一篇: 15管家婆小项目