每日一问:C++拷贝构造函数和赋值构造函数有什么区别?

首先要纠正一下,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;
  • 赋值操作符重载函数应该检查是否是自我赋值,如果是则直接返回当前对象的引用;
  • 赋值操作符重载函数需要执行深拷贝操作,否则会导致指针等资源共享问题。

需要注意的是,赋值操作符重载函数和拷贝构造函数有所区别。拷贝构造函数用于在创建对象时通过复制另一个对象来初始化该对象,而赋值操作符重载函数用于在已有对象被赋值给另一个同类对象时执行初始化操作。

两者区别

拷贝构造函数和赋值函数重载符是两种不同的函数,它们有以下几个主要区别:

  1. 参数类型不同:拷贝构造函数的参数是一个同类对象的引用,用于指定要复制的对象,而赋值函数的参数也是一个同类对象的引用,但是用于赋值操作。

  2. 调用时机不同:拷贝构造函数是在创建新对象时调用,通过复制另一个对象来初始化新对象;而赋值函数是在已有对象被赋值给另一个同类对象时调用,执行初始化操作。

  3. 返回值不同:拷贝构造函数不需要返回任何值,它会自动返回新对象的引用;而赋值函数的返回值是当前对象的引用,因为赋值操作完成后,需要返回当前对象的引用。

  4. 目的不同:拷贝构造函数的主要目的是创建新对象并复制另一个对象的状态,而赋值函数的主要目的是将一个已有对象的状态复制到另一个对象中。

  5. 实现方法不同:拷贝构造函数通常会执行深拷贝操作,以避免资源共享问题;而赋值函数通常会在执行赋值操作之前释放当前对象的资源,以避免内存泄漏问题。

需要注意的是,拷贝构造函数和赋值函数在某些情况下可能会被自动调用,例如当类对象作为参数传递给函数或者从函数中返回时,编译器可能会自动调用拷贝构造函数或者赋值函数。因此,在定义这两个函数时,需要确保它们能够正确地执行所需的操作,以避免出现意外行为。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
拷贝构造函数是用来创建一个新对象并将其初始化为给定对象的副本的特殊成员函数。它通常用于以下情况: - 当一个对象通过值传递给函数或以值的形式返回时 - 当一个对象用另一个对象进行初始化时 - 当一个对象作为另一个对象的成员进行初始化时 对于类`Person`的拷贝构造函数,它会接受一个`const Person&`类型的参数,并将其成员变量`name_`赋值给新创建的对象的`name_`成员变量。 赋值运算符是用于将一个对象的值分配给另一个已经存在的对象的成员函数。它通常用于以下情况: - 当一个对象被另一个对象赋值时 - 当一个对象作为另一个对象的成员进行赋值时 对于类`Person`的赋值运算符,它会接受一个`const Person&`类型的参数,并将其成员变量`name_`赋值给当前对象的`name_`成员变量。然后,它将返回一个指向左侧运算对象的引用,以支持连续赋值的操作。 如果在类定义中没有显式定义拷贝构造函数赋值运算符,编译器会为类生成默认的拷贝构造函数赋值运算符。此外,我们还可以使用`=default`来显式要求编译器生成合成的拷贝构造函数赋值运算符。这将使用默认的实现来完成拷贝和赋值操作。 总之,拷贝构造函数用于创建一个对象的副本,而赋值运算符用于将一个对象的值赋给另一个已经存在的对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++拷贝构造函数与拷贝赋值运算符](https://blog.csdn.net/xiongya8888/article/details/89424224)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值