【C++】类与对象:深入理解默认成员函数

类与对象:深入理解默认成员函数

  • 引言
  • 1、默认成员函数概述
  • 2、构造函数与析构函数
    • 2.1 默认构造函数
    • 2.2 析构函数
  • 3、拷贝控制成员
    • 3.1 拷贝构造函数
    • 3.2 赋值运算符重载
  • 4、移动语义(C++11)
    • 4.1 移动构造函数
    • 4.2 移动赋值运算符
  • 5、三五法则与最佳实践
    • 5.1 三五法则(Rule of Three/Five)
    • 5.2 显式控制
    • 5.3 建议
  • 6、总结

引言

C语言是面向过程的语言,强调函数和结构化编程,而C++在兼容C语言的基础上,增加了面向对象编程、泛型编程等特性。

  • 典型对比
// C:过程式
typedef struct Stack
{
	int* a;
	int top;
	int capacity;
} Stack;

void STInit(Stack* pst);
void STPush(Stack* pst, STDataType x);
// C++:面向对象
class Stack {
public:
    Stack() {}
    void push(int x){}
private:
    int* a_;
    int size_;
    int capcity_;
};

1、默认成员函数概述

  • 在C++中,当定义一个类时,编译器会自动生成6个默认成员函数(C++11起):
    • 默认构造函数
    • 析构函数
    • 拷贝构造函数
    • 赋值运算符重载
    • 移动构造函数(C++11)
    • 移动赋值运算符(C++11)
  • 这些函数在特定场景下会被隐式调用,理解它们的特性和行为对编写健壮的类至关重要。

2、构造函数与析构函数

2.1 默认构造函数

  • 作用:初始化对象成员。
  • 生成条件:当类中没有显示定义任何构造函数时。
  • 特点
    • 对内置类型不做处理(不进行初始化)。
    • 对自定义类型调用其默认构造函数。
  • 示例
class A {
public:
    int x;  // 随机值
    std::string s; // 调用std::string类的默认构造函数
};

int main() {
    A a;
    return 0;
}

[!WARNING]

当显示创建构造函数,编译器就不会生成默认构造函数。

class A {
public:
    A(int x, std::string s) {
        std::cout << "A" << std::endl;
    }
    int x;
    std::string s;
};

int main() {
    A a;
    return 0;
}

显示创建构造函数

2.2 析构函数

  • 作用:释放对象资源。
  • 生成条件:没有显示定义析构函数。
  • 特点
    • 内置类型不做处理。
    • 自定义类型调用其析构函数。
class A {
public:
    A() {
        std::cout << "A()" << std::endl;
    }
    ~A() {
        std::cout << "~A()" << std::endl;
    }
private:
    int x;
    std::string s;
};

int main() {
    A a; 
    // A()
    // ~A()
    return 0;
}

[!CAUTION]

当类管理资源(动态内存、文件句柄等)时,必须手动定义。

class Stack {
public:
    Stack(int n = 4) {
        a_ = (int*)malloc(sizeof(int) * n);
        top_ = 0;
		capacity_ = n;
    }
    ~Stack() {
        free(a_);
        a_ = nullptr;
        top_ = capacity_ = 0;
    }
private:
    int* a_;
    int capacity_;
    int top_;
};

3、拷贝控制成员

3.1 拷贝构造函数

  • 形式T(const T& val)
  • 特点
    • 内置类型不做处理,直接进行值拷贝。
    • 自定义类型调用其拷贝构造函数。

[!IMPORTANT]

如果不显示定义拷贝构造函数,编译器默认进行值拷贝。

class Stack {
public:
    Stack(int n = 4) {
        a_ = (int*)malloc(sizeof(int) * n);
        top_ = 0;
		capacity_ = n;
    }
    ~Stack() {
        free(a_);
        a_ = nullptr;
        top_ = capacity_ = 0;
    }
private:
    int* a_;
    int capacity_;
    int top_;
};

int main() {
    Stack s1;
    Stack s2(s1);
    return 0;
}
  • 调试可观察到:

浅拷贝

s1对象和s2对象内的数据数组具有相同的地址,表明是同一个。

浅拷贝

3.2 赋值运算符重载

  • 形式T& operator=(const T& val)
  • 示例
class Stack {
public:
    Stack(int n = 4) {
        a_ = (int*)malloc(sizeof(int) * n);
        top_ = 0;
        capacity_ = n;
    }
    Stack(const Stack &s) {
        a_ = (int*)malloc(sizeof(int) * capacity_);
        top_ = s.top_;
        capacity_ = s.capacity_;
        for (int i = 0; i < top_; ++i) {
            a_[i] = s.a_[i];
        }
    }
    Stack& operator=(const Stack &s) { // 赋值运算符重载
        if (this != &s) { // 杜绝自己赋值给自己
            free(a_); // 将原数组释放,防止内存泄漏
            a_ = (int*)malloc(sizeof(int) * capacity_);
            top_ = s.top_;
            capacity_ = s.capacity_;
            for (int i = 0; i < top_; ++i) {
                a_[i] = s.a_[i];
            }
        }
        return *this;
    }
    ~Stack() {
        free(a_);
        a_ = nullptr;
        top_ = capacity_ = 0;
    }
private:
    int* a_;
    int capacity_;
    int top_;
};

4、移动语义(C++11)

4.1 移动构造函数

  • 形式T(T&&)
  • 关键:转移资源所有权而非拷贝。
  • 标记:使用noexcept保证异常安全。
class Vector {
public:
    Vector(int n = 4) {
        data_ = new int[n];
        size_ = 0;
        capacity_ = n;
    }
    Vector(Vector&& v) noexcept
        : data_(v.data_), size_(v.size_), capacity_(v.capacity_) {
        v.data_ = nullptr;
        v.size_ = 0;
        v.capacity_ = 0;
    }
    ~Vector() {
        delete[] data_;
        size_ = capacity_ = 0;
    }
private:
    int* data_;
    int size_;
    int capacity_;
};

4.2 移动赋值运算符

  • 形式T& operator=(T&&)
Vector& operator=(Vector&& v) noexcept {
    if (this != &v) {
        data_ = v.data_;
        size_ = v.size_;
        capacity_ = v.capacity_;
        v.data_ = nullptr;
        v.size_ = 0;
        v.capacity_ = 0;
    }
    return *this;
}
  • 生成规则
    • 没有自定义拷贝控制成员时。
    • 类未声明移动操作。
    • 析构函数未显示定义。

5、三五法则与最佳实践

5.1 三五法则(Rule of Three/Five)

  • 需要自定义析构函数 ⇒ \Rightarrow 必须处理拷贝(三法则)。
  • C++11后扩展为五法则(包含移动操作)。

5.2 显式控制

  • =default:显示要求编译器生成默认版本。
  • =delete:禁用特定成员函数。

5.3 建议

  • 优先使用移动语义。
  • 使用智能指针管理资源。
  • 默认使用=default保持代码简洁。

6、总结

成员函数默认行为自定义场景
默认构造函数内置类型不做处理,自定义类型调用其默认构造函数需要特定初始化逻辑
析构函数内置类型不做处理,自定义类型调用其默认析构函数管理资源释放
拷贝构造函数浅拷贝需要深拷贝或禁止拷贝
赋值运算符重载浅拷贝同拷贝构造函数
移动构造函数转移资源(C++11)优化资源转移
移动赋值运算符转移资源(C++11)同移动构造函数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/981016.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LINUX网络基础 - 网络编程套接字,UDP与TCP

目录 前言 一. 端口号的认识 1.1 端口号的作用 二. 初识TCP协议和UDP协议 2.1 TCP协议 TCP的特点 使用场景 2.2 UDP协议 UDP的特点 使用场景 2.3 TCP与UDP的对比 2.4 思考 2.5 总结 三. 网络字节序 3.1 网络字节序的介绍 3.2 网络字节序思考 四. socket接口 …

夸父工具箱(安卓版) 手机超强工具箱

如今&#xff0c;人们的互联网活动日益频繁&#xff0c;导致手机内存即便频繁清理&#xff0c;也会莫名其妙地迅速填满&#xff0c;许多无用的垃圾信息悄然占据空间。那么&#xff0c;如何有效应对这一难题呢&#xff1f;答案就是今天新推出的这款工具软件&#xff0c;它能从根…

Apache nifi demo 实验

Apache nifi 是个数据流系统&#xff0c;可以通过配置 自定义的流程来实现数据的转换。 比如可以配置一个流程&#xff0c;读取数据库里的数据&#xff0c;再转换&#xff0c;最后保存到本地文件。 这样可以来实现一些数据转换的操作&#xff0c;而不用特地编写程序来导入导出。…

VSCode知名主题带毒 安装量900万次

目前微软已经从 Visual Studio Marketplace 中删除非常流行的主题扩展 Material Theme Free 和 Material Theme Icons&#xff0c;微软称这些主题扩展包含恶意代码。 统计显示这些扩展程序的安装总次数近 900 万次&#xff0c;在微软实施删除后现在已安装这些扩展的开发者也会…

Java自动拆箱装箱/实例化顺序/缓存使用/原理/实例

在 Java 编程体系中&#xff0c;基本数据类型与包装类紧密关联&#xff0c;它们各自有着独特的特性和应用场景。理解两者之间的关系&#xff0c;特别是涉及到拆箱与装箱、实例化顺序、区域问题、缓存问题以及效率问题。 一、为什么基本类型需要包装类 泛型与集合的需求 Java…

蓝桥杯复盘记录004(2023)

涉及知识点 1.深搜 2.单调队列滑动窗口 3.位运算 4.并查集 题目 1.lanqiao3505 思路&#xff1a; dfs(index, weight, cnt) index表示瓜的索引&#xff0c; weight等于买瓜的重量&#xff0c; cnt表示买了多少瓜。 递归终止条件&#xff1a;1.如果瓜买完了&#xff0c;归…

【银河麒麟高级服务器操作系统】服务器测试业务耗时问题分析及处理全流程分享

更多银河麒麟操作系统产品及技术讨论&#xff0c;欢迎加入银河麒麟操作系统官方论坛 https://forum.kylinos.cn 了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer…

【现代深度学习技术】卷积神经网络03:填充和步幅

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上&#xff0c;结合当代大数据和大算力的发展而发展出来的。深度学习最重…

FPGA开发,使用Deepseek V3还是R1(3):系统级与RTL级

以下都是Deepseek生成的答案 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;1&#xff09;&#xff1a;应用场景 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;2&#xff09;&#xff1a;V3和R1的区别 FPGA开发&#xff0c;使用Deepseek V3还是R1&#x…

【含文档+PPT+源码】基于SpringBoot和Vue的编程学习系统

项目介绍 本课程演示的是一款 基于SpringBoot和Vue的编程学习系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系统 3.该…

网页复制小妙招

当你遇到网页时不能复制时&#xff0c;不要慌&#xff0c;教你一招可让你为所欲为。 平时你们在网上查找资料想复制时&#xff0c;总是会出现付费限制提示&#xff08;我也是qwq&#xff09;&#xff0c;这时不要慌&#xff0c;在空白处右击选择检查 按开检查&#xff0c;然后…

聆听PostgreSQL数据库的使用

参考&#xff1a;&#xff08;1&#xff09;零基础入门PostgreSQL教程 &#xff08;2&#xff09;菜鸟教程 文章目录 一、PostgreSQL是什么&#xff1f;二、基本使用1.下载2.操作&#xff08;1&#xff09;数据库&#xff08;2&#xff09;表 一、PostgreSQL是什么&#xff1f;…

内核进程调度队列(linux的真实调度算法) ─── linux第13课

目录 内核进程调度队列的过程 一个CPU拥有一个runqueue(运行队列在内存) 活动队列(active) 过期队列(expired) active指针和expired指针 重绘runqueue linux内核O(1)调度算法 总结 补充知识: 封装链式结构的目的是: 仅使用封装链式结构可以得到全部的task_struct的信…

【算法】手撕二分查找

目录 二分查找 【左闭右闭】/【相错终止】 【循环不变量】 【四要素】 二分查找的任意模板 【一般】情形 【左闭右闭】总结 mid的防溢出写法 【左闭右开】/【相等终止】 【一般】情形 再谈初始值 【左闭右开】总结 二分查找本质 【左开右闭】/【相等终止】 【一般…

C++入门基础知识1

今天&#xff0c;我们正式来学习C&#xff0c;由于C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库&#xff0c;以及编程范式等。熟悉C语言之后&#xff0c;对C学习有一定的帮助。 现在我们这篇主要是&#xff1a; 1. 补充C语言语法…

Leetcode 57-插入区间

给你一个 无重叠的 &#xff0c;按照区间起始端点排序的区间列表 intervals&#xff0c;其中 intervals[i] [starti, endi] 表示第 i 个区间的开始和结束&#xff0c;并且 intervals 按照 starti 升序排列。同样给定一个区间 newInterval [start, end] 表示另一个区间的开始和…

【三.大模型实战应用篇】【4.智能学员辅导系统:docx转PDF的自动化流程】

去年团队庆功宴上,我司CTO端着酒杯过来:“老王啊,咱们现在文档解析做得挺溜了,但老师们总抱怨下载的作业格式乱码…” 我看了眼手机里凌晨三点收到的崩溃警报,把杯里的可乐一饮而尽——得,新的副本又开了。 一、为什么PDF转换比想象中难十倍? 某次用户调研中,数学教研…

Mac上安装Pycharm

说明&#xff1a;仅供参考&#xff0c;是自己的安装流程&#xff0c;以免以后自己想不起来来看看的笔记 官网地址&#xff1a;https://www.jetbrains.com/pycharm/ 1、点击Download&#xff0c;跳转到下一个页面 2、MAC&#xff0c;选择Mac OS&#xff0c;在Pycharm Professio…

【动手学强化学习】番外2-多智能体强化学习算法框架之“MARLlib”学习

文章目录 一、待解决问题1.1 问题描述1.2 解决方法 二、方法详述2.1 必要说明2.2 应用步骤2.2.1 调研当前主流的MARL算法框架2.2.2 学习经典MARL算法框架——“MARLlib”&#xff08;1&#xff09;开发团队&#xff08;2&#xff09;简介 2.2.3 安装经典MARL算法框架——“MARL…

VPC2-多域攻击-tomcat渗透-通达oa-域控提权-密码喷射-委派攻击-数据库提权

下载链接: https://pan.baidu.com/s/1nUYj6G9ouj6BcumDgoDaGg 提取码: ejbn jishu域 windows 2008 tomcat渗透 访问发现tomcat 点击manage app 尝试弱口令进入,发现tomcat/tomcat成功进入 用哥斯拉生成后门 然后建立一个文件夹&#xff0c;把它放进去&#xff0c;把它改名…