一起聊聊C++中的特殊成员函数

yizhihongxing

下面我将详细讲解一下C++中特殊成员函数的相关知识。

一起聊聊C++中的特殊成员函数

什么是特殊成员函数

在C++中,除了一些普通的成员函数,还有一些被称为特殊成员函数的成员函数。这些特殊成员函数包括:

  • 默认构造函数
  • 拷贝构造函数
  • 移动构造函数
  • 拷贝赋值运算符
  • 移动赋值运算符
  • 析构函数

这些函数被称为特殊成员函数的原因是它们都在特定的情况下被自动调用,无需显式调用。

默认构造函数

默认构造函数是一种没有参数的构造函数,它在创建对象时被自动调用,用来初始化对象的成员变量。如果我们没有定义默认构造函数,那么编译器会为我们自动生成一个默认构造函数。

class MyClass {
public:
    MyClass() {
        // 构造函数的实现
    }
};

需要注意的是,如果我们在类中定义了其他构造函数,那么编译器就不会为我们生成默认构造函数,这时如果我们需要默认构造函数,就需要显式地定义它。

也可以把默认构造函数定义为被删除的函数,这样编译器在需要默认构造函数时就不能自动生成。

class MyClass {
public:
    MyClass() = delete;
};

拷贝构造函数

拷贝构造函数是一种特殊的构造函数,用来在创建新对象时,将一个已有的对象的值赋值给新对象。拷贝构造函数的参数为该类的另一个对象的引用。

class MyClass {
public:
    MyClass(const MyClass& other) {
        // 拷贝构造函数的实现
    }
};

需要注意的是,如果我们不定义拷贝构造函数,编译器会为我们自动生成一个默认的拷贝构造函数,该函数会对类的每个成员变量执行浅拷贝操作。如果我们的类中有指针类型的成员变量,就需要显式定义拷贝构造函数,以执行深拷贝操作。

class MyClass {
public:
    MyClass(const MyClass& other) {
        this->p = new int(*other.p); // 深拷贝
    }

private:
    int* p;
};

移动构造函数

移动构造函数也是一种特殊的构造函数,它在创建新对象时使用一个临时对象的值,避免了拷贝操作,提高了程序的效率。移动构造函数的参数为一个右值引用。

class MyClass {
public:
    MyClass(MyClass&& other) {
        // 移动构造函数的实现
    }
};

需要注意的是,如果我们不定义移动构造函数,编译器会为我们自动生成一个默认的移动构造函数,该函数会对类的每个成员变量执行浅拷贝操作。如果我们的类中有指针类型的成员变量,就需要显式定义移动构造函数,以执行浅拷贝操作。

class MyClass {
public:
    MyClass(MyClass&& other) {
        // 移动构造函数的实现
        this->p = other.p;  // 浅拷贝
        other.p = nullptr;
    }

private:
    int* p;
};

拷贝赋值运算符

拷贝赋值运算符用来在已经存在的对象之间赋值。拷贝赋值运算符的参数为该类的另一个对象的引用。在实现拷贝赋值运算符时,需要注意要进行自我赋值的判断。

class MyClass {
public:
    MyClass& operator=(const MyClass& other) {
        // 拷贝赋值运算符的实现
        if (this == &other) {  // 自我赋值
            return *this;
        }
        delete this->p;  // 释放原有的内存
        this->p = new int(*other.p);  // 深拷贝
        return *this;
    }

private:
    int* p;
};

移动赋值运算符

移动赋值运算符也是在已经存在的对象之间赋值,它使用一个临时对象的值,避免了拷贝操作,提高了程序的效率。移动赋值运算符的参数为一个右值引用。

class MyClass {
public:
    MyClass& operator=(MyClass&& other) {
        // 移动赋值运算符的实现
        delete this->p;  // 释放原有的内存
        this->p = other.p;  // 浅拷贝
        other.p = nullptr;
        return *this;
    }

private:
    int* p;
};

析构函数

析构函数是对于一个对象而言最后会被执行的函数,用来释放对象所占用的资源。当对象在程序中被删除,或销毁时,会自动调用析构函数。

class MyClass {
public:
    ~MyClass() {
        // 析构函数的实现
        delete this->p;
    }

private:
    int* p;
};

需要注意的是,如果我们的类中有指针类型的成员变量,需要在析构函数中显式地释放内存,否则会造成内存泄漏。

示例

下面是一个使用特殊成员函数示例:

#include <iostream>

class MyClass {
public:
    MyClass() {
        std::cout << "调用默认构造函数" << std::endl;
        this->p = new int(0);
    }

    MyClass(const MyClass& other) {
        std::cout << "调用拷贝构造函数" << std::endl;
        this->p = new int(*other.p);  // 假设p是指针类型的成员变量
    }

    MyClass(MyClass&& other) {
        std::cout << "调用移动构造函数" << std::endl;
        this->p = other.p;
        other.p = nullptr;
    }

    MyClass& operator=(const MyClass& other) {
        std::cout << "调用拷贝赋值运算符" << std::endl;
        if (this == &other) {
            return *this;
        }
        delete this->p;
        this->p = new int(*other.p);
        return *this;
    }

    MyClass& operator=(MyClass&& other) {
        std::cout << "调用移动赋值运算符" << std::endl;
        delete this->p;
        this->p = other.p;
        other.p = nullptr;
        return *this;
    }

    ~MyClass() {
        std::cout << "调用析构函数" << std::endl;
        delete this->p;
    }

private:
    int* p;
};

int main() {
    MyClass obj1;  // 调用默认构造函数
    MyClass obj2(obj1);  // 调用拷贝构造函数
    MyClass obj3(std::move(obj1));  // 调用移动构造函数
    MyClass obj4;
    obj4 = obj2;  // 调用拷贝赋值运算符
    obj4 = std::move(obj2);  // 调用移动赋值运算符
    return 0;
}

输出结果为:

调用默认构造函数
调用拷贝构造函数
调用移动构造函数
调用默认构造函数
调用拷贝赋值运算符
调用移动赋值运算符
调用析构函数
调用析构函数
调用析构函数
调用析构函数

其中,obj1的值被移动到obj3中,obj2的值被拷贝到obj4中,各个对象的特殊成员函数被自动调用。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一起聊聊C++中的特殊成员函数 - Python技术站

(1)
上一篇 2023年6月8日
下一篇 2023年4月18日

相关文章

  • SQL Server 2008 新特性 总结复习(一)

    SQL Server 2008 新特性 总结复习(一) SQL Server 2008 是微软公司开发的一款数据库管理系统软件,它具有很多新特性,本文将会对其中一些新特性进行详细讲解。 1. 影响行的Trigger 在 SQL Server 2008 中,Trigger 变得更加强大了,它可以使用 inserted 和 deleted 表来访问触发器所在表中…

    C# 2023年6月1日
    00
  • ASP.NET Core 实现自动刷新JWT Token

    在ASP.NET Core中,JWT(JSON Web Token)是一种常见的身份验证机制。JWT Token有一个过期时间,当Token过期时,用户需要重新登录以获取新的Token。本攻略将深入探讨如何在ASP.NET Core中实现自动刷新JWT Token,并提供两个示例说明。 实现自动刷新JWT Token 在ASP.NET Core中,您可以使用…

    C# 2023年5月17日
    00
  • C#操作Byte数组和十六进制进行互转

    下面是详细讲解“C#操作Byte数组和十六进制进行互转”的完整攻略。 操作Byte数组和十六进制互转的准备工作 在C#中,我们可以使用byte数组来存储字节序列,用十六进制字符串来表示这些字节。在进行互转之前,需要对这些数据进行一些准备工作。 创建Byte数组 创建byte数组的方法很简单,可以使用byte[]关键字。 byte[] byteArray = …

    C# 2023年6月7日
    00
  • C#规则引擎RulesEngine的具体使用

    C#规则引擎RulesEngine是一个开源的规则引擎,它让定义和运行业务规则变得更加容易。本文将介绍如何使用C#规则引擎RulesEngine,包括如何定义规则、如何使用规则引擎来执行规则以及如何测试规则。 安装RulesEngine 安装C#规则引擎RulesEngine非常简单,只需要在项目中通过NuGet安装RulesEngine包就可以了。 Ins…

    C# 2023年5月31日
    00
  • asp.net 多字段模糊查询代码

    请允许我详细讲解一下实现 ASP.NET 多字段模糊查询的完整攻略。以下是步骤和代码示例: 1. 创建 ASP.NET Web 应用程序 首先,在 Visual Studio 中创建一个 ASP.NET Web 应用程序。选择“Web Application(.NET Framework)”模板,名称为“MultiFieldFuzzySearch”,创建一个…

    C# 2023年5月31日
    00
  • SQL数据库实例名称找不到或远程连接失败并显示错误error40的原因及解决办法

    问题描述:如果你在连接SQL数据库时遇到了“SQL数据库实例名称找不到或远程连接失败并显示错误error40”的错误提示,那么就表示你的SQL服务器无法建立与此实例的连接。 原因分析:此问题多数是由以下几个因素造成的: SQL Server服务没有启动或启动了错误的服务名,导致实例名称无法链接; 防火墙阻止了对数据库的连接; SQL Server实例没有启用…

    C# 2023年5月15日
    00
  • C#编写网游客户端的实现

    C#编写网游客户端的实现 在编写网游客户端时,我们需要基于C#开发。C#是一种由微软开发的通用、面向对象的编程语言,被广泛应用于Windows平台上的应用程序开发、游戏开发、Web开发等领域。 下面是实现网游客户端的完整攻略: 步骤一:选择开发工具 C#代码编写需要使用集成开发环境(IDE),以下是常用的C#开发工具: Visual Studio(免费或付费…

    C# 2023年6月3日
    00
  • c# FTP上传文件实例代码(简易版)

    下面是针对“c# FTP上传文件实例代码(简易版)”这篇文章的详细讲解攻略。 1. 什么是FTP上传? FTP(文件传输协议)是一种用来在网络上传递文件的协议。FTP上传即是将本地文件通过FTP协议上传到远程FTP服务器,从而实现将文件在不同计算机之间进行传输的目的。 2. c# FTP上传文件实例代码说明 2.1 前置条件 在进行c# FTP上传文件前,需…

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