目录
如果类中有动态分配的对象,就必须显式地定义构造函数和赋值操作符,以确保对象被正确复制
编译器一般会给四种方法生成默认版本:
默认构造函数、析构函数、复制构造函数、赋值操作符
复制构造函数会根据已有对象创建一个新对象,默认生成的复制构造函数,会根据已有对象成员变量进行浅copy。
下面是调用到复制构造函数的地方:
- 对象以传值方式传递给方法或返回
- 对象使用下述语法初始化:Myclass a = b;
- 对象位于在花括号中的初始化列表内
- 对象在异常中被抛出或捕获
赋值操作符用来将一个对象的值赋给另一个对象:a = b,它与复制构造函数的区别在于,被赋值的对象已经存在了。
实现赋值操作符有一些指导原则:
- 为右侧操作数使用const引用
- 以引用方式返回*this,以支持操作符链
- 在设置新状态前销毁已存在的状态
- 通过比较this和&rth检测自赋值(a=a)
如果你想创建不能被客户复制的对象(只能是引用对象),则应该将复制构造函数和赋值操作符声明为类的私有成员,或者使用boost::nocopyable
如果类分配了资源,一般来说,析构函数和复制构造函数、赋值操作符是要一起使用的。
(声明用于子类化的空虚析构函数是特例,因为它没有执行实际的内存释放操作),这样的概念被表述为"类的正统规范形式"
像下面的代码就会编译报错,因为x和y的析构函数都试图释放相同的内存。
class Array{
public:
explicit Array(int size): mSize(size), mData(new int[size])
{
}
~Array() {
delete[] mData;
};
int Get(int index) const;
void Set(int index, int value);
int GetSize() const;
private:
int mSize;
int* mData;
};
int main() {
{
Array x(100);
Array y = x;
}
std::cout << "end" << std::endl;
return 0;
}
明确告诉编译器生成一个私有默认构造函数和一个虚析构函数,且两个函数均使用编译器生成的版本。
class MyClass
{
public:
virtual ~MyClass() = default;
private:
MyClass() = default;
};
class NonCopyable
{
public:
NonCopyable() = default;
NonCopyable(const NonCopyable&) = delete;
NonCopyable & operator=(const NonCopyable&) = delete;
};
这样禁止生成复制构造函数和赋值操作符,也可以使得某个类不可复制。
定义构造函数和赋值操作符
cpp文件
h文件
// // Created by hanhandi on 2023/3/12. // #ifndef UNTITLED_MYARRAY_H #define UNTITLED_MYARRAY_H #include <string> class Array{ public: // 默认构造函数 Array(); // 非默认构造函数 explicit Array(int size); // 析构函数 ~Array(); // 复制构造函数 Array(const Array& i_array); // 赋值操作符 Array& operator=(const Array& i_array); std::string Get(int index) const; bool Set(int index, const std::string& str); int GetSize() const; private: int mSize; std::string* mArray; }; #endif //UNTITLED_MYARRAY_H#include <iostream> #include "MyArray.h" int main() { Array a; // 默认构造函数 Array b(10); // 非默认构造函数 Array c(b); // 复制构造函数 Array d = a; // 复制构造函数 b = c; // 赋值操作符 std::cout << "end" << std::endl; return 0; }
No comments yet.