《C++文章匯總》
上一篇介紹了引用和匯編《05-匯編補充&面向對象》,本文介紹封裝、內存布局和堆空間。
1.封裝
#include <iostream>
using namespace std;
struct Person {
private:
int m_age;
public:
void setAge(int age){
if (age < 0) {
m_age = 1;
}else{
m_age = age;
}
}
int getAge(){
return m_age;
}
};
int main(){
Person person;
person.setAge(10);
cout << "age:" << person.getAge() << endl;
return 0;
}
//輸出
age:10
2.內存空間布局
? 每個應用都有自己獨立的內存空間,其內存空間一般都有以下幾大區域
代碼段(代碼區)
? 用于存放代碼
數據段(全局區)
? 用于存放全局變量等
棧空間
? 每調用一個函數就會給它分配一段連續的棧空間,等函數調用完畢后會自動回收這段棧空間 ? 自動分配和回收
堆空間
? 需要主動去申請和釋放
3.堆空間
? 在程序運行過程,為了能夠自由控制內存的生命周期、大小,會經常使用堆空間的內存
? 堆空間的申請\釋放
一一對應關系
malloc \ free
new \ delete
new [] \ delete []
x86 32bit環境,指針變量占用4個字節
?注意
申請堆空間成功后,會返回那一段內存空間的地址
申請和釋放必須是1對1的關系,不然可能會存在內存泄露
? 現在的很多高級編程語言不需要開發人員去管理內存(比如Java),屏蔽了很多內存細節,利弊同時存在
利:提高開發效率,避免內存使用不當或泄露
弊:不利于開發人員了解本質,永遠停留在API調用和表層語法糖,對性能優化無從下手
堆空間初始化
void test3(){
int *p = (int *)malloc(4);
*p = 0;
//將4個字節中的每一個字節都設置為1,并不是將4個字節設置為1
int size = sizeof(int) * 10;
int *q = (int *)malloc(size);
//momery set
memset(q, 0, size);
//從p地址開始的連續4個字節中的每一個字節都設置為1
//memset(q,1,4);
//將4個字節設置為1
//00000000 00000000 00000000 00000001
//將4個字節中的每一個字節都設置為1
//00000001 00000001 00000001 00000001
}
堆空間new的時候初始化
void test4(){
int *p0 = new int;//Mac平臺會初始化為0,Windows平臺未初始化
int *p1 = new int();
int *p2 = new int(5);
cout << *p0 << endl;
cout << *p1 << endl;
cout << *p2 << endl;
}
//輸出
0
0
5
memset函數是將較大的數據結構(比如對象、數組等)內存清零的比較快的方法
圖片.png
4.對象的內存
? 對象的內存可以存在于3種地方
全局區(數據段):全局變量
棧空間:函數里面的局部變量
堆空間:動態申請內存(malloc、new等)
struct Person {
int m_age;
};
//全局區
Person g_person;
int main(){
//棧空間
Person person;
//堆空間
Person *per = new Person;
}
5.構造函數Constructor
? 構造函數(也叫構造器),在對象創建的時候自動調用,一般用于完成對象的初始化工作
struct Person {
int m_age;
Person(){
m_age = 0;
cout << "Person()" << endl;
}
Person(int age){
m_age = age;
cout << "Person(int age)" << endl;
}
void display(){
cout << m_age << endl;
}
};
int main(){
Person person1;
person1.display();
Person person2(20);
person2.display();
Person person3(30);
person3.display();
getchar();
return 0;
}
//輸出
Person()
0
Person(int age)
20
Person(int age)
30
?特點
函數名與類同名,無返回值(void都不能寫),可以有參數,可以重載,可以有多個構造函數
一旦自定義了構造函數,必須用其中一個自定義的構造函數來初始化對象,若不調用會報錯
struct Person {
int m_age;
// Person(){
// m_age = 0;
// cout << "Person()" << endl;
// }
Person(int age){
m_age = age;
cout << "Person(int age)" << endl;
}
void display(){
cout << m_age << endl;
}
};
int main(){
Person person1;//會報錯,Person()構造函數被注釋了
person1.display();
Person person2(20);
person2.display();
Person person3(30);
person3.display();
getchar();
return 0;
}
?注意
通過malloc分配的對象不會調用構造函數
struct Car {
int m_price;
Car(){
cout << "Car::car()" << endl;
}
void run(){
cout << "Car::run " << m_price << endl;
}
};
int main(){
Car car;//調用構造函數
Car *c = new Car;//調用構造函數
delete c;
Car * cc = (Car *)malloc(sizeof(Car));//沒有調用構造函數
cc->m_price = 10;
cc->run();
}
//輸出
Car::car()
Car::car()
Car::run 10
? 一個廣為流傳的、很多教程\書籍都推崇的錯誤結論:
默認情況下,編譯器會為每一個類生成空的無參的構造函數
正確理解:在某些特定的情況下,編譯器才會為類生成空的無參的構造函數
? (哪些特定的情況?以后再提)
struct Teacher {
int m_age;
// Teacher(){
// cout << "Teacher()" << endl;
// }
};
int main(){
Teacher teacher;
teacher.m_age = 10;//不會默認生成構造函數
}
函數聲明和構造函數易混淆:4個無參,3個有參,一共創建了7個Person對象,有兩個是函數聲明,并沒有創建Person對象
struct Person {
int m_age;
Person(){
m_age = 0;
cout << "Person()" << endl;
}
Person(int age){
m_age = age;
cout << "Person(int age)" << endl;
}
void display(){
cout << m_age << endl;
}
};
Person g_person0;//Person()
Person g_person1();//函數聲明
Person g_person2(20);//Person(int age)
int main(){
Person person0;//Person()
Person person1();//函數聲明
Person person2(20);//Person(int age)
Person *p0 = new Person;//Person()
Person *p1 = new Person();//Person()
Person *p2 = new Person(20);//Person(int age)
//4個無參,3個有參,一共創建了7個Person對象,有兩個是函數聲明,并沒有創建Person對象
getchar();
return 0;
}
//輸出
Person()
Person(int age)
Person()
Person(int age)
Person()
Person()
Person(int age)
6.成員變量初始化
I.沒有自定義構造函數的情況下:new Person()堆空間成員變量初始化為0,棧空間沒有初始化成員變量,里面是中斷代碼cccccccc
struct Person {
int m_age;
};
//全局區:成員變量初始化為0
Person g_person;
int main(){
//棧空間:沒有初始化成員變量,里面是cccccccc
Person person;
//堆空間:Windows沒有初始化成員變量,Mac初始化了成員變量
Person *p0 = new Person;
//堆空間:成員變量初始化為0
Person *p1 = new Person();
cout << g_person.m_age << endl;
cout << person.m_age << endl;//Windows報錯
cout << p0->m_age << endl;
cout << p1->m_age << endl;
getchar();
return 0;
}
//輸出
0
86053
0
0
II.自定義了構造函數,但沒有對成員變量賦值初始化,Windows和Mac平臺下,全局區依然初始化成員變量為0
Windows平臺下Person *p0 = new Person堆空間沒有初始化成員變量,
Windows平臺下Person *p0 = new Person()堆空間沒有初始化成員變量,編譯器認為自定義了構造函數,會自己初始化成員變量,編譯器不再幫忙初始化成員變量
Mac平臺下堆空間初始化成員變量為0
圖片.png
? 如果自定義了構造函數,除了全局區,其他內存空間的成員變量默認都不會被初始化,需要開發人員手動初始化
struct Person {
int m_age;
Person(){
};
};
//全局區:成員變量初始化為0
Person g_person;
int main(){
//棧空間:沒有初始化成員變量,里面是cccccccc
Person person;
//堆空間:Windows沒有初始化成員變量,Mac初始化了成員變量
Person *p0 = new Person;
//堆空間:Windows沒有初始化成員變量,Mac初始化了成員變量
Person *p1 = new Person();
cout << g_person.m_age << endl;
cout << person.m_age << endl;//Windows報錯
cout << p0->m_age << endl;
cout << p1->m_age << endl;
getchar();
return 0;
}
//輸出
0
86053
0
0
Windows下Person對象數組,沒有自定義構造函數,成員變量都為0,自定義了構造函數,成員變量未初始化
Mac下均初始化為0
struct Person {
int m_age;
//Person(){
//};
};
int main(){
Person *p = new Person[3]();
cout << p[0].m_age << endl;
}
windows下為0
struct Person {
int m_age;
Person(){
};
};
int main(){
Person *p = new Person[3]();
cout << p[0].m_age << endl;
}
windows下為-842150451,顯然沒有初始化
struct Person {
int m_age;
//Person(){
//};
};
int main(){
Person *p = new Person[3]{};
cout << p[0].m_age << endl;
}
windows下為0
struct Person {
int m_age;
Person(){
};
};
int main(){
Person *p = new Person[3]{};
cout << p[0].m_age << endl;
}
windows下為-842150451,顯然沒有初始化
7.對象初始化,對象所有成員變量清零
Person(){
memset(this, 0, sizeof(Person));
};
8.析構函數Destructor
?析構函數(也叫析構器),在對象銷毀的時候自動調用,一般用于完成對象的清理工作
?特點
函數名以~開頭,與類同名,無返回值(void都不能寫),無參,不可以重載,有且只有一個析構函數
?注意
通過malloc分配的對象free的時候不會調用析構函數
?構造函數、析構函數要聲明為public,才能被外界正常使用
struct Person {
int m_age;
Person(){
memset(this, 0, sizeof(Person));
cout << "Person Person()" << endl;
};
~Person(){
cout << "Person ~Person()" << endl;
}
};
int main(){
cout << 1 << endl;
{
Person person;
}
cout << 2 << endl;
getchar();
return 0;
}
//輸出
1
Person Person()
Person ~Person()
2
malloc函數創建的對象不會調用析構函數
struct Person {
int m_age;
Person(){
memset(this, 0, sizeof(Person));
cout << "Person Person()" << endl;
};
~Person(){
cout << "Person ~Person()" << endl;
}
};
int main(){
Person * p = (Person *)malloc(sizeof(Person));
free(p);
}
//沒有打印輸出
new Person會調用析構函數
struct Person {
int m_age;
Person(){
memset(this, 0, sizeof(Person));
cout << "Person Person()" << endl;
};
~Person(){
cout << "Person ~Person()" << endl;
}
};
int main(){
Person *p = new Person;
delete p;
}
//輸出
Person Person()
Person ~Person()
查看當前平臺棧空間堆空間的地址大小
int main(){
Person *p = new Person;
//堆空間的地址值
cout << p << endl;
//棧空間的地址值
cout << &p << endl;
delete p;
}
//輸出:棧空間的地址值0x7ffeefbff480大于堆空間地址值0x1004b6370
Person Person()
0x1004b6370
0x7ffeefbff480
Person ~Person()