一、类
- C++中可以使用struct、class两个关键字来定义一个类
- struct和class的区别
- struct的默认成员权限是public
- class的默认成员权限是private
- 实际开发中,用class表示类的比较多,因为涉及到封装的思想
- 在函数中创建的对象,都是在栈空间,比如下面图片中的person对象、p指针的内存都是在函数的栈空间,会自动分配和回收内存
二、对象的内存布局
一般情况下,对象中的成员变量是在内存中连续存放的,对象的名称指向存放成员变量的首地址的位置。
比如下面的代码:
其内存地址如下图:
三、this
- this是指向当前对象的指针
- 对象在调用成员函数的时候,会自动传入当前对象的内存地址
- 因为this是指针,必须使用this->m_age的方式来访问成员变量
四、封装
封装指的是将成员变量私有化,提供公共的getter和setter给外界去访问成员变量
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(-4);
cout << person.getAge() << endl;
return 0;
}
五、内存空间的布局
- 每个应用都有自己独立的内存空间,其内存空间一般有以下几大区域
- 代码段(代码区):用于存放代码
- 数据段(全局区):用于存放全局变量等
- 栈空间
- 每调用一个函数就会给它分配一段连续的栈空间,等函数调用完毕后自动回收这段栈空间
- 自动分配和回收
- 堆空间:需要主动去申请和释放
- 堆空间的特点
- 在程序运行过程中,为了能够自由控制内存的生命周期、大小,会经常使用堆空间的内存
- 堆空间申请和对应的释放函数
- malloc --> free
- new --> delete
- new[] --> delete[]
- 堆空间的使用注意事项
- 申请堆空间成功后,会返回那一段内存空间的地址
- 申请和释放必须是一一对应的,不然可能会纯在内存泄漏的问题
- 在函数中创建一个指针,指向堆空间的一个地址,内存图如下图(32位)
- 堆空间的初始化
- 对于直接分配内存,malloc直接分配的地址不会初始化,memset可以批量初始化地址
- 对于用new的方式申请的内存,在类型后面加上括号的方法可以初始化
- memset函数时将较大的数据结构(比如对象、数组等)内存直接初始化的比较快的方法
- 对于直接分配内存,malloc直接分配的地址不会初始化,memset可以批量初始化地址
六、对象的内存
- 对象的内存可以存放于3中地方
- 全局区(数据段):全局变量
- 栈空间:函数里面的局部变量
- 堆空间:动态申请的内存(malloc、new等)
- 类中包含其他类的情况,如果类被创建在函数的栈空间,包含的类的对象也会被分配到栈空间,并且内存空间相邻
- 类中包含其他类的情况,如果外面的类是被new对象分配到堆空间,那么包含的类对象也会被创建在堆空间,并且地址相邻
七、构造函数(Constructor)
- 构造函数(也叫构造器),在对象创建的时候自动调用,一般用于完成对象的初始化工作
- 特点
- 函数名与类同名,无返回值(void都不能写),可以有参数,可以重载(可以有多个构造函数,包括复制构造函数)
- 一旦自定义了构造函数,必须用其中一个自定义的构造函数来初始化对象
- 注意:通过malloc分配的对象不会调用构造函数
- 在某些特定的情况下,编译器才会为类生成空的无参构造函数
- 构造函数的调用情况如下图
- 默认情况下,全局区定义变量会直接初始化成员变量,其他区域要在类型后面加括号才能初始化,具体情况如下图:
- 如果对象中都是基础类型,在构造函数中可以调用memset方法批量初始化对象
八、析构函数(Destructor)
- 析构函数(也叫析构器),在对象销毁的时候自动调用,一般用于完成对象的清理工作
- 函数名以~开头,与类同名,无返回值(void都不能写),无参,不可以重载,有且只有一个析构函数
- 注意:用malloc分配的对象free的时候不会调用析构函数
- 构造函数、析构函数都要声明为public,才能被外界正常使用
- 对象内部申请的堆空间,由对象内部回收,否则会出现内存泄漏的情况
- 外面的对象即使创建在栈空间,内部创建的堆空间对象也要由对象回收
- 外面的对象即使创建在栈空间,内部创建的堆空间对象也要由对象回收
九、声明和实现分离
- 一般对象申明在h文件中,实现在cpp文件中
十、命名空间
- 命名空间可以用来避免名字的冲突
- 命名空间不影响内存布局
- 命名空间的嵌套,命名空间可以嵌套,适用时需要指定嵌套关系
- 有个默认的全局命名空间,我们创建的命名空间默认都嵌套在它的里面
- 命名空间的合并:以下2中写法是等价的
- 在声明和实现分离的场景中,可以指定相同的命名空间
后记
个人总结,欢迎转载、评论、批评指正