《C++文章汇总》
上一篇介绍了引用和汇编《05-汇编补充&面向对象》,本文介绍封装、内存布局和堆空间。
1.封装
#include
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函数是将较大的数据结构(比如对象、数组等)内存清零的比较快的方法
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
◼ 如果自定义了构造函数,除了全局区,其他内存空间的成员变量默认都不会被初始化,需要开发人员手动初始化
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()