C++中一些易混淆的基础知识
文章目录
本文总结C++中容易混淆的概念。
1 常见易混淆知识点
1.1 内存控制
1.1.1 malloc/free, new/delete的区别
- malloc和free是C/C++语言的标准库函数,而new/delete是C++的运算符。它们都可以用于动态申请和释放内存。
- new/delete运算符不仅可以申请/释放内存,还可以对申请的对象进行初始化和销毁操作。
- C++既可以使用new/delete,也可以调用malloc/free。而C语言只能用malloc/free管理动态内存。
1.1.2 new/delete
- new/delete就是C++的运算符。new的全称为new operator, delete的全称为delete operator。其作用是为分配并初始化一个对象数组。
C++执行new操作实际上后台执行了以下3步操作:
- 调用operate new或者operate new []的标准库函数。该函数分配一块原始的、足够大的、未命名的存储特定类型对象的空间;
- 编译器运行相应的构造函数以构造这些特定对象(或对象数组);
- 对象被构造完成并分配的空间,返回一个指向该对象的指针。
C++执行delete操作实际上后台执行了以下2步操作:
- 对所指向的对象或者对象数组执行对应的析构函数;
- 编译器调用operate delete(或者operate delete[])的标准库函数释放内存空间。
使用示例:
|
|
1.1.3 operate new/delete
- operate new/delte是C++的标准函数。用于用于为特定类型的对象分配或者释放内存空间。operate new/delete的函数原型定义如下:
|
|
如果应用程序希望自己控制内存的分配和释放,就需要自己定义operate new和operate delete函数,从而让编译器使用自定义的版本替换标准库中定义的版本。
应用程序可以在全局作用域中定义oprerate new/delete函数或者定义为类的成员函数。
如果分配或者释放的的对象是类对象,则首先在类中查找是否有自定义的oprerate new/delete函数。若没查找到,再到全局作用域中查找。
我们也可以直接指定查找全局作用域的函数:使用::new ::delete可以指定查找全局作用域的函数。
因为operate new用在构造函数之前而operate delete用在对象销毁之后,所以这两个成员函数必须是静态函数,而且不能操作类的任何数据成员。
例外:不能重载以下形式的operate new函数:
|
|
这种形式只供标准库使用,不能被用户重新定义。
温馨提示:
实际上C++也有和operate new/delete功能相似的标准库allocator类,用于为指定类型的对象分配内存。它非配的内存是原始、未构造的。
1.1.4 placement new
placement new用于对使用operate new的方式申请的内存上构造对象。placement new的几种形式:
|
|
其中place_address必须是一个指针,同时在initializers中提供一个(可能为空)的逗号分隔的初始化列表,该初始值列表用于构造新分配的对象。
1.1.5 智能指针
1.1.5.1 shared_ptr
1.1.5.2 unique_ptr
1.1.5.3 weak_ptr
1.2 指针与引用的区别
- 指针本身就是一个对象,其内容是某个内存单元的地址,允许对指针赋值和拷贝;而引用并非对象,它只是一个已经存在的对象的一个别名。
- 指针在它的生命周期内可以指向不同的对象;而引用一旦初始化完成,将和它的初始值始终绑定在一起。
- 指针无须在定义时赋初值;而引用必须初始化,绑定到一个已经存在的对象。指针可以为空,但引用不可以。
- sizeof操作指针和引用的结果不同;sizeof操作引用得到的是引用所绑定的对象的大小;而sizeof操作指针得到的是指针本身的大小。
- 引用是类型安全的,而指针不是。
1.3 struct和class的区别
- struct的成员(成员函数和数据成员)的访问控制属性默认是共有的;而class的成员默认是私有的。
- struct的继承默认是共有继承,而class的默认继承方式是私有的。
1.4 const修饰常量与define的区别
- const定义的常量在编译阶段进行处理;#define定义的常量在预处理阶段进行处理;
- const定义的常量要进行类型检查;#define定义的常量只是简单的文本替换,没有类型,不进行类型检查;
- const定义的常量要分配内存;#define定义的常量为宏定义,不需要分配内存;
- const定义的常量存放在数据区,只有一份拷贝;#define定义的常量不分配存储空间,使用过程中只是简单的执行文本替换;
1.5 重载覆盖隐藏的区别
1.5.1 重载
重载的特点:
- 相同的范围(在同一个类中)
- 函数名字相同
- 参数不同
- virtual 关键字可有可无
1.5.2 覆盖
覆盖是指派生类函数覆盖基类虚函数。其特征为:
- 不同的范围(分别位于派生类与基类);
- 函数名字相同
- 参数相同
- 基类函数必须有virtual 关键字
1.5.3 隐藏
“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
- 如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
- 如果派生类的函数与基类的函数同名,并且参数也相同而且基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)
1.5.4 覆盖隐藏的示例
|
|