C++ 类成员函数全家桶

ghy / 2023-06-19 / 原文

RAII

Resource Acquisition Is Initialization,资源获取即初始化

这是一种解决资源管理问题的方法,将资源的有效期与持有资源的对象的生命期严格绑定,由对象的构造函数完成资源的分配,由析构函数完成资源的释放
C++借助构造函数和析构函数,解决了传统的 malloc & freenew & delete 管理资源方法无法有效应对复杂资源管理场景的问题

对于资源管理需求,无GC机制的C++语言提供了基于析构函数的RAII方法和智能指针,有GC机制的Java语言提供了垃圾回收机制(Garbage Collection,GC).需要注意的是,虽然它们都能避免发生内存泄漏问题,但实现原理并不相同.

首先,从语言的设计角度来说,C++的设计应用场景要求其对代码的执行过程做到可控,RAII方法仍然需要手动释放资源,而GC机制并不需要开发者手动释放资源(这也是RAII方法和GC机制的一个显著区别),
即RAII并没有剥夺开发者手动管理资源的权限,它只是通过构造和析构函数提供了一种安全管理资源的方法,开发者对于执行过程是具有控制权的.而GC机制把资源的回收过程交由JVM负责,开发者无权控制.

关于可控性,还体现在析构函数和垃圾回收发生的时机上,在C++中通过{}来界定作用范围,当超出作用范围后即会调用对象的析构函数,即析构函数的调用时间是可预知的(适用于对时序有严格要求的场景),而垃圾回收机制的发生时间取决于JVM的资源管理策略,是开发者无权控制的.

前言

资源管理和类的控制实际是两个分离的过程,RAII方法则是利用类的成员函数解决资源管理的方法之一

普通构造函数

无参

  1. 自定义
    1.1 普通形式
    1.2 使用初始化表达式

  2. 默认
    POD陷阱(哪些类型不会自动初始化为0,大括号指定初始化值(0初始化方式))或等号指定初始化值(无法采用小括号指定初始化值)
    支持单纯的大括号初始化,等号和大括号同时使用的初始化方式

当自定义构造函数后,默认无参构造函数就不存在了,可通过default生成默认的无参构造函数

单参数

此时单参数的构造函数,实现了从一种类型隐式地转换为类类型,因此此时的构造函数也称为转换构造函数,需要注意的是C++ 类型转换中提到的编译器只支持一步隐式类型转换规则.

如果想禁止这种隐式类型转换,可以使用explicit关键字修饰单参数的构造函数,此时该构造函数只能通过直接初始化使用,编译器也不会在隐式类型转换过程中调用该构造函数

额外需要注意的是explicit关键字只能出现在类内部构造函数声明处

多参数

  1. 普通形式
  2. 使用初始化表达式
    explicit禁止隐式转换(我自己说的,具体作用要查一下)

拷贝构造函数(copy constructor)

  • 定义了用同类型的另一个对象初始化本对象时的操作

拷贝构造函数特征

  • 第一个参数是自身类型引用
  • 额外参数均存在默认值
  • 存在几种情况需要被隐式使用,因此通常不设置为explicit
  • 可通过delete禁用拷贝构造函数
拷贝构造函数示例代码
class Foo {
public:
  Foo();
  Foo(const Foo&);
};

移动构造函数(move constructor)

  • 定义了用同类型的另一个对象初始化本对象时的操作
  • C++11 引入

移动操作需要理清左值和右值的概念,了解新的右值引用概念

拷贝赋值运算符(copy-assignment operator)

  • 定义了将一个对象赋值同类型的另一个对象时的操作

移动赋值运算符(move-assignment operator)

  • 定义了将一个对象赋值同类型的另一个对象时的操作
  • C++11 引入

解构(析构)函数(destructor)

定义了对象销毁时的操作