首先要纠正一下,C++中没有“赋值构造函数”,对应的是“赋值操作符重载函数”(operator=函数)。下面
C++拷贝构造函数
C++类的拷贝构造函数是一种特殊的构造函数,用于在创建对象时通过复制另一个对象来初始化该对象。拷贝构造函数的参数是一个同类对象的引用,用于指定要复制的对象。
拷贝构造函数的语法如下:
class MyClass {
public:
MyClass(); // 默认构造函数
MyClass(const MyClass& other); // 拷贝构造函数
};
可以看到,拷贝构造函数的函数名与类名相同,并且只有一个参数,即另一个同类对象的引用。拷贝构造函数通常用于以下几种情况:
- 通过已有对象初始化新对象;
class MyClass {
public:
MyClass(); // 默认构造函数
MyClass(const MyClass& other); // 拷贝构造函数
};
MyClass obj1; // 调用默认构造函数
MyClass obj2 = obj1; // 调用拷贝构造函数
- 将对象作为参数传递给函数时,由于参数是按值传递的,因此需要使用拷贝构造函数创建副本;
void myFunc(MyClass obj);
MyClass obj1;
myFunc(obj1); // 调用拷贝构造函数
- 从函数返回对象时,同样需要使用拷贝构造函数创建副本。
MyClass myFunc();
MyClass obj = myFunc(); // 调用拷贝构造函数
如果在没有定义拷贝构造函数的情况下,编译器会提供一个默认的拷贝构造函数,该函数执行的是浅拷贝(即只复制指针或者基本数据类型),如果类中有指针等需要深拷贝的数据成员,那么就需要自定义拷贝构造函数以执行深拷贝操作。
C++赋值操作符重载函数
在C++中,类可以通过重载赋值操作符(也称为赋值运算符或赋值函数)来自定义对象的赋值行为。默认情况下,C++提供的赋值操作符只是简单地将一个对象的值复制到另一个对象中,这在一些情况下并不符合实际需求。
赋值操作符重载函数的语法如下:
class MyClass {
public:
MyClass(); // 默认构造函数
MyClass(const MyClass& other); // 拷贝构造函数
MyClass& operator=(const MyClass& other); // 赋值操作符重载函数
可以看到,赋值操作符重载函数的函数名为"operator=",返回值为当前类对象的引用,参数也是一个同类对象的引用。赋值操作符重载函数通常用于以下几种情况:
- 当已有对象被赋值给另一个同类对象时,需要执行初始化操作;
class MyClass {
public:
MyClass& operator=(const MyClass& other); // 赋值操作符重载函数
};
MyClass obj1, obj2;
obj2 = obj1; // 调用赋值操作符重载函数
- 支持深度复制
class MyClass {
public:
MyClass& operator=(const MyClass& other); // 赋值操作符重载函数
private:
int* data_;
};
MyClass& MyClass::operator=(const MyClass& other) {
if (this != &other) {
// 释放当前对象的资源
delete data_;
// 执行深拷贝
data_ = new int(*other.data_);
}
return *this;
}
MyClass obj1, obj2;
obj2 = obj1; // 调用赋值操作符重载函数
在这个例子中,对象包含一个指针类型的成员变量data_,在赋值操作符重载函数中,需要执行深拷贝操作,以避免资源共享问题。如果不执行深拷贝操作,两个对象将共享相同的内存,可能会导致不可预期的行为。
- 在链式赋值操作中,需要将多个同类对象赋值给当前对象。
在这个例子中,链式赋值操作可以将多个同类对象赋值给当前对象obj1。赋值操作符重载函数将obj2的状态复制到obj1中,返回一个引用给obj1,然后继续将obj3的状态复制到obj2中,最终完成链式赋值操作。注意,setValue函数也返回一个引用,以支持链式调用。
class MyClass {
public:
MyClass& operator=(const MyClass& other); // 赋值操作符重载函数
MyClass& setValue(int value); // 设置值的函数
private:
int value_;
};
MyClass& MyClass::operator=(const MyClass& other) {
if (this != &other) {
value_ = other.value_;
}
return *this;
}
MyClass& MyClass::setValue(int value) {
value_ = value;
return *this;
}
MyClass obj1, obj2, obj3;
obj1.setValue(1).setValue(2).setValue(3); // 链式赋值操作
obj2.setValue(4).setValue(5).setValue(6);
obj3.setValue(7).setValue(8).setValue(9);
obj1 = obj2 = obj3; // 链式赋值操作
在定义赋值操作符重载函数时,需要注意以下几点:
- 赋值操作符重载函数的返回值必须是当前类对象的引用,因为赋值操作完成后,需要返回当前对象的引用;
- 赋值操作符重载函数不会改变传入对象的状态,因此应该将其声明为const;
- 赋值操作符重载函数应该检查是否是自我赋值,如果是则直接返回当前对象的引用;
- 赋值操作符重载函数需要执行深拷贝操作,否则会导致指针等资源共享问题。
需要注意的是,赋值操作符重载函数和拷贝构造函数有所区别。拷贝构造函数用于在创建对象时通过复制另一个对象来初始化该对象,而赋值操作符重载函数用于在已有对象被赋值给另一个同类对象时执行初始化操作。
两者区别
拷贝构造函数和赋值函数重载符是两种不同的函数,它们有以下几个主要区别:
-
参数类型不同:拷贝构造函数的参数是一个同类对象的引用,用于指定要复制的对象,而赋值函数的参数也是一个同类对象的引用,但是用于赋值操作。
-
调用时机不同:拷贝构造函数是在创建新对象时调用,通过复制另一个对象来初始化新对象;而赋值函数是在已有对象被赋值给另一个同类对象时调用,执行初始化操作。
-
返回值不同:拷贝构造函数不需要返回任何值,它会自动返回新对象的引用;而赋值函数的返回值是当前对象的引用,因为赋值操作完成后,需要返回当前对象的引用。
-
目的不同:拷贝构造函数的主要目的是创建新对象并复制另一个对象的状态,而赋值函数的主要目的是将一个已有对象的状态复制到另一个对象中。
-
实现方法不同:拷贝构造函数通常会执行深拷贝操作,以避免资源共享问题;而赋值函数通常会在执行赋值操作之前释放当前对象的资源,以避免内存泄漏问题。
需要注意的是,拷贝构造函数和赋值函数在某些情况下可能会被自动调用,例如当类对象作为参数传递给函数或者从函数中返回时,编译器可能会自动调用拷贝构造函数或者赋值函数。因此,在定义这两个函数时,需要确保它们能够正确地执行所需的操作,以避免出现意外行为。