1. 构造函数(通常有5类)
1.1 默认构造函数(没有参数)
- 通常没有参数,但它们可以具有具有默认值的参数。
- 如果未在类中声明任何构造函数,编译器将提供隐式默认 inline 构造函数。
- 如果声明了任何非默认构造函数,编译器不会提供默认构造函数:
- 以通过将编译器定义为已删除 来阻止编译器生成隐式 默认构造函数:
1.2 重载构造函数(多个参数)
1.3 拷贝构造函数
- 定义复制构造函数时,还应定义拷贝赋值运算符 (=)
- 可以通过将拷贝构造函数定义为已删除来防止复制对象
String(const String& s) = delete;
// 拷贝构造函数可能具有以下签名之一:
Box(Box& other); // Avoid if possible--allows modification of other.
Box(const Box& other);
Box(volatile Box& other);
Box(volatile const Box& other);
// Additional parameters OK if they have default values
Box(Box& other, int i = 42, string label = "Box");
1.4 拷贝赋值构造函数
String& operator=(const String& s)
1.5 移动构造函数
它采用左值引用作为第一个参数,任何其他参数都必须具有默认值。Box(Box&& other);
以一个String类的设计为例:
class String {
public:
// 0. 默认构造函数 Default constructor,通常没有参数,但可以具有默认值得参数
String() {
m_str = new char[1];
m_str[0] = '\0';
m_size = 0;
}
String() : m_size(0) {
m_str = new char[1];
m_str[0] = '\0';
}
// 1. 重载构造函数(多个参数)
explicit String(char *str = "") {
if (str == nullptr) {
m_str = new char[1];
m_str[0] = '\0';
m_size = 0;
// C++中的任何字符串的长度至少为1(即至少包含一个结束符‘\0’)。空字符串也是有效的字符串,它的长度为1,因此他代表一块合法的内存单元而不是NULL。
} else {
int len = strlen(str);
m_str = new char[len + 1];
strcpy_s(m_str, len + 1, str);
m_size = len;
}
}
// 2. 拷贝构造函数 Copy constructor. - 深拷贝
String(const String& s) {
m_str = new char[s.m_size + 1];
strcpy(m_str, s.m_str);
m_size = s.m_size;
}
// 3. 拷贝赋值构造函数 Copy assignment operator.
String& operator=(const String& s) {
if (this != &s) { // 检查自赋值
delete[] m_str;
m_size = s.m_size;
m_str = new char[m_size + 1];
strcpy(m_str, s.m_str);
}
return *this; //为了支持链式访问 eg: s3 = s2 = s1;
}
// 4. 移动构造函数 Move constructor
// 采用一个对类类型的右值引用作为参数
String(String&& s) noexcept : m_str(nullptr), m_size(0) {
m_str = s.m_str;
m_size = s.m_size;
s.m_str = nullptr;
s.m_size = 0;
// *this = std::move(s);
}
// Move constructor的另一种写法
String(String&& s) noexcept : m_str(nullptr), m_size(0) {
*this = std::move(s);
// 如果为你的类同时提供了移动构造函数和移动赋值运算符,
// 则可以编写移动构造函数来调用移动赋值运算符,从而消除冗余代码。
}
// 5. 移动赋值构造函数
String& operator=(const String&& s) noexcept {
if (this != &s) {
delete[] m_str;
m_str = s.m_str;
m_size = s.m_size;
s.m_str = nullptr;
s.m_size = 0;
}
return *this;
}
~String() {
if (m_str != nullptr) {
delete[] m_str;
}
}
char *GetPtr() { return m_str; }
private:
int m_size; // 当前字符串长度
char *m_str; // 指向字符串的指针
};
2 析构函数
析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。