1. 构造函数(通常有5类)

1.1 默认构造函数(没有参数)

  1. 通常没有参数,但它们可以具有具有默认值的参数。
  2. 如果未在类中声明任何构造函数,编译器将提供隐式默认 inline 构造函数
  3. 如果声明了任何非默认构造函数,编译器不会提供默认构造函数:
  4. 以通过将编译器定义为已删除 来阻止编译器生成隐式 默认构造函数

String() = delete;

1.2 重载构造函数(多个参数)

1.3 拷贝构造函数

  1. 定义复制构造函数时,还应定义拷贝赋值运算符 (=)
  2. 可以通过将拷贝构造函数定义为已删除来防止复制对象

String(const String& s) = delete;

  1. // 拷贝构造函数可能具有以下签名之一:
  2. Box(Box& other); // Avoid if possible--allows modification of other.
  3. Box(const Box& other);
  4. Box(volatile Box& other);
  5. Box(volatile const Box& other);
  6. // Additional parameters OK if they have default values
  7. Box(Box& other, int i = 42, string label = "Box");

1.4 拷贝赋值构造函数

String& operator=(const String& s)

1.5 移动构造函数

它采用左值引用作为第一个参数,任何其他参数都必须具有默认值。
Box(Box&& other);
以一个String类的设计为例:

  1. class String {
  2. public
  3. // 0. 默认构造函数 Default constructor,通常没有参数,但可以具有默认值得参数
  4. String() {
  5. m_str = new char[1];
  6. m_str[0] = '\0';
  7. m_size = 0;
  8. }
  9. String() : m_size(0) {
  10. m_str = new char[1];
  11. m_str[0] = '\0';
  12. }
  13. // 1. 重载构造函数(多个参数)
  14. explicit String(char *str = "") {
  15. if (str == nullptr) {
  16. m_str = new char[1];
  17. m_str[0] = '\0';
  18. m_size = 0;
  19. // C++中的任何字符串的长度至少为1(即至少包含一个结束符‘\0’)。空字符串也是有效的字符串,它的长度为1,因此他代表一块合法的内存单元而不是NULL。
  20. } else {
  21. int len = strlen(str);
  22. m_str = new char[len + 1];
  23. strcpy_s(m_str, len + 1, str);
  24. m_size = len;
  25. }
  26. }
  27. // 2. 拷贝构造函数 Copy constructor. - 深拷贝
  28. String(const String& s) {
  29. m_str = new char[s.m_size + 1];
  30. strcpy(m_str, s.m_str);
  31. m_size = s.m_size;
  32. }
  33. // 3. 拷贝赋值构造函数 Copy assignment operator.
  34. String& operator=(const String& s) {
  35. if (this != &s) { // 检查自赋值
  36. delete[] m_str;
  37. m_size = s.m_size;
  38. m_str = new char[m_size + 1];
  39. strcpy(m_str, s.m_str);
  40. }
  41. return *this; //为了支持链式访问 eg: s3 = s2 = s1;
  42. }
  43. // 4. 移动构造函数 Move constructor
  44. // 采用一个对类类型的右值引用作为参数
  45. String(String&& s) noexcept : m_str(nullptr), m_size(0) {
  46. m_str = s.m_str;
  47. m_size = s.m_size;
  48. s.m_str = nullptr;
  49. s.m_size = 0;
  50. // *this = std::move(s);
  51. }
  52. // Move constructor的另一种写法
  53. String(String&& s) noexcept : m_str(nullptr), m_size(0) {
  54. *this = std::move(s);
  55. // 如果为你的类同时提供了移动构造函数和移动赋值运算符,
  56. // 则可以编写移动构造函数来调用移动赋值运算符,从而消除冗余代码。
  57. }
  58. // 5. 移动赋值构造函数
  59. String& operator=(const String&& s) noexcept {
  60. if (this != &s) {
  61. delete[] m_str;
  62. m_str = s.m_str;
  63. m_size = s.m_size;
  64. s.m_str = nullptr;
  65. s.m_size = 0;
  66. }
  67. return *this;
  68. }
  69. ~String() {
  70. if (m_str != nullptr) {
  71. delete[] m_str;
  72. }
  73. }
  74. char *GetPtr() { return m_str; }
  75. private
  76. int m_size; // 当前字符串长度
  77. char *m_str; // 指向字符串的指针
  78. };

2 析构函数

析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。