拷贝构造函数

一、概述

拷贝构造函数是一种特殊的构造函数,用于创建对象的副本,其形参是本类对象的引用。当使用一个对象来初始化另一个对象时,或者将一个对象作为参数传递给函数,或者从函数返回一个对象时,都会涉及到对象的复制。在这些情况下,如果类没有显式定义拷贝构造函数,编译器会生成一个默认的拷贝构造函数,该构造函数将执行浅拷贝(即简单地复制对象的成员变量值)。但是,在某些情况下,特别是当类包含指针成员变量时,浅拷贝可能会导致意外的行为,例如浅拷贝只会复制指针的值,而不会复制指针所指向的对象,这可能导致多个对象共享同一块内存,进而导致潜在的内存管理错误。

因此,为了确保正确的对象复制,可以在类中显式定义拷贝构造函数。拷贝构造函数的定义方式与普通的构造函数类似,但其参数为该类的一个引用(通常是const引用),用于接收要复制的对象。通过显式定义拷贝构造函数,你可以确保在对象复制时执行适当的深拷贝操作,从而避免意外的行为。例如Point p2(p1);

二、拷贝构造函数的特点

  1. 复制对象:拷贝构造函数的主要作用是复制一个对象,就像复制一张照片一样。通过拷贝构造函数,你可以创建一个新的对象,该对象的属性和原来的对象一模一样。

  2. 参数是一个对象:拷贝构造函数的参数是一个对象,它是用来被复制的对象。该函数只有一个参数,并且是同类对象的引用。

  3. 用于赋值和传递:拷贝构造函数通常在对象赋值和传递的时候被调用。比如,当你把一个对象赋值给另一个对象,或者把一个对象作为函数的参数传递时,拷贝构造函数就会被使用。

  4. 默认生成:如果你没有显式地定义拷贝构造函数,编译器会自动生成一个默认的拷贝构造函数。程序员可以自定义拷贝构造函数,用于按照需要初始化新对象。

三、自定义拷贝构造函数

假设我们有一个类 Person,代表一个人,其中包含姓名和年龄两个属性。我们将创建一个拷贝构造函数,用于将一个 Person 对象的属性复制到另一个对象。

#include <iostream>
#include <string>

// 定义 Person 类
class Person {
private:
    std::string name;
    int age;

public:
    // 构造函数,用于初始化对象
    Person(std::string newName, int newAge) {
        name = newName;
        age = newAge;
    }

    // 拷贝构造函数,用于复制对象
    Person(const Person& other) {
        // 将另一个对象的属性复制到当前对象
        name = other.name;
        age = other.age;
    }

    // 打印个人信息的成员函数
    void printInfo() {
        std::cout << "Name: " << name << ", Age: " << age << std::endl;
    }
};

int main() {
    // 创建一个 Person 对象
    Person person1("Alice", 30);

    // 使用拷贝构造函数创建另一个 Person 对象
    Person person2 = person1;

    // 打印两个对象的信息
    std::cout << "Person 1: ";
    person1.printInfo();  // 输出:Name: Alice, Age: 30

    std::cout << "Person 2: ";
    person2.printInfo();  // 输出:Name: Alice, Age: 30

    return 0;
}

四、怎样使用默认拷贝构造函数

#include <iostream>
#include <string>

class Person {
private:
    std::string name;
    int age;

public:
    // 构造函数
    Person(std::string newName, int newAge) : name(newName), age(newAge) {}

    // 打印个人信息
    void printInfo() {
        std::cout << "Name: " << name << ", Age: " << age << std::endl;
    }
};

int main() {
    // 创建一个对象 person1
    Person person1("Alice", 30);

    // 使用代入法创建一个新对象 person2,并将 person1 的值赋给它
    Person person2(person1);

    // 使用赋值法创建一个新对象 person3,并将 person1 的值赋给它
    Person person3("Bob", 25);
    person3 = person1;

    // 打印三个对象的信息
    std::cout << "Person 1: ";
    person1.printInfo();  // 输出:Name: Alice, Age: 30

    std::cout << "Person 2: ";
    person2.printInfo();  // 输出:Name: Alice, Age: 30

    std::cout << "Person 3: ";
    person3.printInfo();  // 输出:Name: Alice, Age: 30

    return 0;
}

五、调用拷贝构造函数的几种情况

  1. 直接初始化:当你直接使用另一个对象来初始化一个新对象时,拷贝构造函数会被调用。

    MyClass obj1(10); // 调用 MyClass(int) 构造函数
    MyClass obj2(obj1); // 调用拷贝构造函数 MyClass(const MyClass&)
    
  2. 间接初始化:当你使用赋值语句将一个对象的值赋给另一个对象时,拷贝构造函数也会被调用。

    MyClass obj1(10); // 调用 MyClass(int) 构造函数
    MyClass obj2 = obj1; // 调用拷贝构造函数 MyClass(const MyClass&)
  3. 函数参数传递:当你将对象作为参数传递给函数时,拷贝构造函数也会被调用。

    void function(MyClass obj) {
        // 在这里拷贝构造函数 MyClass(const MyClass&) 被调用
    }
    
    MyClass obj1(10);
    function(obj1);
  4. 函数返回值:当函数返回一个对象时,拷贝构造函数同样会被调用。

    MyClass function() {
        MyClass obj(10);
        return obj; // 调用拷贝构造函数 MyClass(const MyClass&)
    }
    
    MyClass obj2 = function();
    

  • 24
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值