深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结

以下是深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结:

构造函数的调用过程

  • 当一个对象被创建的时候,其构造函数会被自动调用;
  • 如果该类没有定义构造函数,则系统会为该类自动生成一个默认构造函数;
  • 如果该类存在构造函数,则必须在用户的代码中显式地调用构造函数;
  • 如果一个类有多个构造函数,则在创建对象时可以根据需要选择其中之一来使用;
  • 构造函数调用顺序为:基类先于派生类,而成员对象的初始化顺序则是它们在类定义中出现的顺序。
#include <iostream>

using namespace std;

class Person {
public:
    Person() {
        cout << "调用了默认构造函数" << endl;
    }

    Person(int age) {
        cout << "调用了带参数的构造函数" << endl;
    }
};

int main() {
    Person p1;      // 调用默认构造函数,输出:调用了默认构造函数
    Person p2(20);  // 调用带参数的构造函数,输出:调用了带参数的构造函数
    return 0;
}

拷贝构造函数的调用过程

  • 当使用一个已经存在的对象去初始化同类对象时,将会调用拷贝构造函数。对象可以直接作为参数传递给函数或从函数中返回时,也会调用拷贝构造函数;
  • 如果该类没有定义拷贝构造函数,则系统会为该类自动生成一个默认拷贝构造函数;
  • 自定义的拷贝构造函数需要将传入的对象的属性值复制到新创建的对象中;
  • 如果一个类有多个构造函数,则在创建对象时可以根据需要选择其中之一来使用。
#include<iostream>
using namespace std;
class Person {
public:
    int age;
    char *name;
    Person() : age(0), name(NULL) {
        cout << "默认构造函数被调用" << endl;
    }
    Person(int age_, char *name_) : age(age_), name(name_) {
        cout << "带参数的构造函数被调用" << endl;
    }
    Person(const Person &p) {
        cout << "拷贝构造函数被调用" << endl;
        this->age = p.age;
        // 复制字符串时需要开辟新的存储空间,保证不会影响原对象
        if (p.name != NULL) {
            this->name = new char[strlen(p.name) + 1];
            strcpy(this->name, p.name);
        }
    }
    ~Person() {
        cout << "析构函数被调用" << endl;
        if (name != NULL) { delete[]name; }
    }
};
void print(const Person& p) {
    cout << "Person age: " << p.age << ", name: " << p.name << endl;
}
int main() {
    Person p1(20, "Tom"); // 调用带参数构造函数
    print(p1);
    Person p2(p1);        // 调用拷贝构造函数
    print(p2);
    return 0;
}

赋值操作符的调用过程

  • 当用一个对象去初始化另一个同类对象时会调用拷贝构造函数,但是当对象之间发生赋值操作时,则会调用赋值操作符;
  • 如果该类没有定义赋值操作符,则系统会为该类自动生成一个默认赋值操作符;
  • 自定义的赋值操作符需要将传入的对象的属性值复制到当前对象中,同时防止出现自赋值的情况,即判断传入的对象是否是当前对象。
#include<iostream>
using namespace std;
class Person {
public:
    int age;
    char *name;
    Person() : age(0), name(NULL) {
        cout << "默认构造函数被调用" << endl;
    }
    Person(int age_, char *name_) : age(age_), name(name_) {
        cout << "带参数的构造函数被调用" << endl;
    }
    Person(const Person &p) {
        cout << "拷贝构造函数被调用" << endl;
        this->age = p.age;
        // 复制字符串时需要开辟新的存储空间,保证不会影响原对象
        if (p.name != NULL) {
            this->name = new char[strlen(p.name) + 1];
            strcpy(this->name, p.name);
        }
    }
    ~Person() {
        cout << "析构函数被调用" << endl;
        if (name != NULL) { delete[]name; }
    }
    Person operator=(const Person &p) {
        cout << "赋值操作符被调用" << endl;
        if (this == &p) { // 自赋值的判断
            return *this;
        }
        this->age = p.age;
        if (this->name != NULL) { delete[]name; } // 先删除当前对象中已有的字符串变量
        if (p.name != NULL) { // 复制字符串并开辟新的存储空间
            this->name = new char[strlen(p.name) + 1];
            strcpy(this->name, p.name);
        }
        return *this;
    }
};
void print(const Person& p) {
    cout << "Person age: " << p.age << ", name: " << p.name << endl;
}
int main() {
    Person p1(20, "Tom"); // 调用带参数构造函数
    print(p1);
    Person p2;        // 调用默认构造函数
    p2 = p1;          // 调用赋值操作符函数
    print(p2);
    return 0;
}

析构函数的调用过程

  • 对象在销毁时,系统会自动调用其析构函数;
  • 当对象为局部自动对象时,程序在此对象的作用域结束时会自动调用其析构函数;
  • 如果该类没有定义析构函数,则系统会为该类自动生成一个默认析构函数;
  • 自定义的析构函数需要释放对象在创建过程中所占用的动态分配的内存空间。
#include<iostream>
using namespace std;
class Person {
public:
    Person() {
        cout << "默认构造函数被调用" << endl;
    }
    ~Person() {
        cout << "析构函数被调用" << endl;
    }
};
int main() {
    Person p; // 调用默认构造函数
    return 0; // 调用析构函数
}

以上就是深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结的攻略,我们可以看到,构造函数,拷贝构造函数,赋值操作符以及析构函数都是类的重要组成部分,它们的正确使用对于保证程序的稳定性非常重要。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • Golang 的defer执行规则说明

    当前站点为标准的Markdown格式化文本提供支持。Markdown是一种轻量级的标记语言,通常由程序员和写作者使用,以便轻松将文本转换为HTML。 Golang 的defer执行规则说明 什么是defer defer是Golang中一个非常有用的关键字,用于确保函数调用在程序执行完当前代码块之后执行。defer被经常用于处理控制流,资源清理等任务,它为代码…

    C 2023年5月23日
    00
  • Linux折腾记(八):使用GCC和GNU Binutils编写能在x86实模式运行的16位代码

    Linux折腾记(八)的主题是如何使用GCC和GNU Binutils编写能在x86实模式运行的16位代码。针对这个主题,我们可以分为以下几步。 步骤1:准备工作 在开始编写代码之前,我们需要安装在Ubuntu系统上安装GCC和GNU Binutils。可以使用以下命令进行安装: sudo apt-get update sudo apt-get instal…

    C 2023年5月23日
    00
  • ECMAScript6变量的解构赋值实例详解

    ECMAScript6变量的解构赋值实例详解 什么是解构赋值 解构赋值是ES6中的一个新特性,它允许你从数组或者对象中提取出数据并赋值到新的变量中。 数组解构赋值 let [a, b, c] = [1, 2, 3]; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 数组解构赋值中,…

    C 2023年5月23日
    00
  • C语言实现简单计算器功能(2)

    当我们实现一个简单的计算器功能时,需要考虑以下几个方面: 用户输入的合法性检查 进行算术运算的函数实现 错误处理和提示信息输出 第一步,我们需要先获取用户输入的表达式,并对其进行合法性检查。用户输入的表达式应该是一个合法的算术表达式,不能含有非法字符,比如字母等。我们可以使用正则表达式来判断用户输入的内容是否合法。 示例1: #include <reg…

    C 2023年5月23日
    00
  • C++实现LeetCode(642.设计搜索自动补全系统)

    下面是C++实现LeetCode设计搜索自动补全系统(642题)的完整攻略。 问题描述 实现一个搜索自动补全系统,可以支持以下功能: 给定一个字符串prefix,返回所有下一个可能的查询已经它们的出现次数,按照次数排列(降序); 插入一个句子sentence时,插入这个句子的所有前缀。 输入的所有字符串都只包含小写字母,且长度不会超过1000。 示例: 输入…

    C 2023年5月23日
    00
  • C语言实现文件读写功能流程

    C语言可以通过文件读写功能来读取文件中的数据内容或者将程序的数据写入到文件中,以实现数据的持久化操作。下面是C语言实现文件读写功能的完整攻略,包括文件读操作和文件写操作。 文件读操作 1. 打开文件 使用fopen函数打开文件,函数原型如下: FILE *fopen(const char *filename, const char *mode); filen…

    C 2023年5月23日
    00
  • C++面向对象之类和对象那些你不知道的细节原理详解

    C++面向对象之类和对象那些你不知道的细节原理详解 什么是类 类是C++中定义自己的数据类型的方法。类可看作是一种用户自定义的数据结构。 我们可以通过定义变量来定义一个类的对象,这个对象就包含了类的属性和操作。 类的基本组成 成员变量 成员变量是类的属性,也称为数据成员、字段或属性。 相当于结构体中的成员变量,可以是任何C++数据类型,包括另一个类的对象。 …

    C 2023年5月23日
    00
  • java jni调用c函数实例分享(java调用c函数)

    下面我将为您详细讲解“Java JNI调用C函数实例分享(Java调用C函数)”的攻略。 什么是JNI? JNI全称为Java Native Interface,即Java本地接口。它是一个开发者提供的桥梁,用于将Java虚拟机(JVM)连接到应用程序中的非Java代码(如C语言、C++等)。使用JNI可以使Java程序调用C语言等非java语言编写的代码或…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部