C++ 类和对象(二):默认成员函数详解

C++ 类和对象(二):默认成员函数详解

        在 C++ 面向对象编程中,类的默认成员函数是非常重要的概念。当我们没有显式实现某些成员函数时,编译器会自动生成它们,这些函数被称为默认成员函数。本文将详细介绍 C++ 类的 6 个默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载以及取地址运算符重载。

一、默认成员函数概述

默认成员函数是指用户没有显式实现,编译器会自动生成的成员函数。一个类在我们不写任何成员函数的情况下,编译器会默认生成以下 6 个默认成员函数:构造函数析构函数拷贝构造函数赋值运算符重载普通取地址运算符重载const 取地址运算符重载

        其中前 4 个是我们需要重点掌握的,后两个在大多数情况下使用编译器自动生成的即可。另外,C++11 以后还增加了两个默认成员函数:移动构造和移动赋值,本文暂不讨论。

二、构造函数

        构造函数是一种特殊的成员函数,其作用是在对象实例化时初始化对象,替代了我们以前手动调用的Init函数,并且会自动调用。

构造函数的特点:函数名与类名相同无返回值(不需要写void对象实例化时系统会自动调用对应的构造函数可以重载若未显式定义,编译器会生成无参的默认构造函数;一旦用户显式定义,编译器不再生成无参构造函数、全缺省构造函数、编译器默认生成的构造函数都称为默认构造函数(不传实参即可调用),且这三者不能同时存在编译器默认生成的构造函数对内置类型成员变量的初始化不确定,对自定义类型成员变量会调用其默认构造函数

构造函数示例

#include <iostream> using namespace std; class Date { public: // 无参构造函数 Date() { _year = 1; _month = 1; _day = 1; } // 带参构造函数 Date(int year, int month, int day) { _year = year; _month = month; _day = day; } // 全缺省构造函数(不能与无参构造同时存在) // Date(int year = 1, int month = 1, int day = 1) // { // _year = year; // _month = month; // _day = day; // } void Print() { cout << _year << "/" << _month << "/" << _day << endl; } private: int _year; int _month; int _day; }; int main() { Date d1; // 调用无参构造函数 Date d2(2025, 1, 1); // 调用带参构造函数 // 注意:以下写法是函数声明,不是对象实例化 // Date d3(); return 0; }

        大多数情况下,我们需要自己实现构造函数。只有少数情况,如类的成员都是自定义类型且这些自定义类型有合适的默认构造函数时(如用两个 Stack 实现队列),编译器自动生成的构造函数才够用。

三、析构函数

        析构函数的功能并不是销毁对象本身(对象在生命周期结束时会自动销毁),而是完成对象中资源的清理释放工作,类比我们之前实现的Destroy函数。

析构函数的特点析构函数名是在类名前加上~无参数无返回值(不需要写void一个类只能有一个析构函数,若未显式定义,系统会自动生成对象生命周期结束时,系统会自动调用析构函数编译器自动生成的析构函数对内置类型成员不做处理,对自定义类型成员会调用其析构函数即使显式定义了析构函数,自定义类型成员的析构函数也会被自动调用没有申请资源的类(如 Date)可以不写析构函数;有资源申请的类(如 Stack)必须自己写析构函数,否则会造成资源泄漏局部域的多个对象,后定义的先析构

析构函数示例

#include<iostream> using namespace std; typedef int STDataType; class Stack { public: Stack(int n = 4) { _a = (STDataType*)malloc(sizeof(STDataType) * n); if (nullptr == _a) { perror("malloc申请空间失败"); return; } _capacity = n; _top = 0; } // 析构函数:释放资源 ~Stack() { cout << "~Stack()" << endl; free(_a); _a = nullptr; _top = _capacity = 0; } private: STDataType* _a; size_t _capacity; size_t _top; }; // 两个Stack实现队列 class MyQueue { public: // 编译器默认生成的析构函数会调用Stack的析构函数 ~MyQueue() { cout << "~MyQueue()" << endl; } private: Stack pushst; Stack popst; }; int main() { Stack st; MyQueue mq; // 析构顺序:~MyQueue() -> ~Stack()(popst) -> ~Stack()(pushst) -> ~Stack()(st) return 0; }

四、拷贝构造函数

        拷贝构造函数是一种特殊的构造函数,用于用一个已存在的对象初始化一个新创建的对象。

拷贝构造函数的特点是构造函数的一个重载第一个参数必须是自身类类型对象的引用,使用传值方式会引发无穷递归调用;可以有多个参数,但后续参数必须有缺省值C++ 规定自定义类型对象进行拷贝行为必须调用拷贝构造(如传值传参、传值返回)若未显式定义,编译器会生成默认拷贝构造函数,对内置类型成员进行值拷贝 / 浅拷贝,对自定义类型成员调用其拷贝构造成员全是内置类型且无资源的类(如 Date)不需要显式实现;有资源的类(如 Stack)需要显式实现深拷贝,否则会导致双重释放传值返回会产生临时对象并调用拷贝构造;传引用返回可减少拷贝,但需确保返回对象在函数结束后仍存在

拷贝构造函数示例

#include <iostream> using namespace std; class Date { public: Date(int year = 1, int month = 1, int day = 1) { _year = year; _month = month; _day = day; } // 拷贝构造函数 Date(const Date& d) // 使用const引用避免修改原对象 { _year = d._year; _month = d._month; _day = d._day; } void Print() { cout << _year << "/" << _month << "/" << _day << endl; } private: int _year; int _month; int _day; }; int main() { Date d1(2025,11,30); d1.Print(); // 2025/11/30 // 拷贝构造 Date d2(d1); d2.Print(); // 2025/11/30 Date d3 = d2; // 也是拷贝构造 d3.Print(); // 2025/11/30 return 0; }

深拷贝实现(以 Stack 为例)

// 栈的深拷贝构造 Stack(const Stack& st) { // 对指针指向的资源重新申请空间并复制数据 _a = (STDataType*)malloc(sizeof(STDataType) * st._capacity); if (nullptr == _a) { perror("malloc申请空间失败!!!"); return; } memcpy(_a, st._a, sizeof(STDataType) * st._top); _top = st._top; _capacity = st._capacity; }
深 / 浅拷贝区别浅拷贝:按字节拷贝,对于指针成员只拷贝地址,不拷贝资源,可能导致多个对象共享同一份资源深拷贝:不仅拷贝指针本身,还对指针指向的资源重新申请空间并复制数据,每个对象拥有独立的资源

五、赋值运算符重载

        赋值运算符重载用于完成两个已存在对象之间的拷贝赋值,与拷贝构造的区别是:拷贝构造用于用已有对象初始化新对象,而赋值重载用于两个已存在对象之间的赋值。

运算符重载基础运算符重载是具有特殊名字的函数,形式为operator运算符重载运算符的参数个数与运算对象数量一致,一元运算符 1 个参数,二元运算符 2 个参数若为成员函数,第一个参数为隐式的this指针,因此参数比运算对象少一个不能重载的运算符:.*::sizeof?:.重载操作符至少有一个类类型参数前置 ++ 和后置 ++ 的区分:后置 ++ 重载时增加一个int形参<<>>建议重载为全局函数,以符合使用习惯

赋值运算符重载的特点必须重载为成员函数参数建议为const当前类类型引用,避免传值拷贝返回值建议为当前类类型引用,支持连续赋值未显式实现时,编译器会生成默认赋值重载,行为与默认拷贝构造类似(内置类型浅拷贝,自定义类型调用其赋值重载)有资源的类需要显式实现深拷贝的赋值重载

赋值运算符重载示例

// 赋值运算符重载 Date& operator=(const Date& d) { // 避免自己给自己赋值 if (this != &d) { _year = d._year; _month = d._month; _day = d._day; } return *this; // 支持连续赋值 } // 使用示例 int main() { Date d1(2025, 11, 30); Date d2(2025, 12, 1); d1 = d2; // 赋值重载,两个已存在对象 Date d3(d2); // 拷贝构造,用d2初始化新对象d3 Date d4 = d2; // 拷贝构造,不是赋值 return 0; }

六、取地址运算符重载

        取地址运算符重载分为普通取地址和 const 取地址两种,一般情况下编译器自动生成的即可满足需求,不需要显式实现

const成员函数

        const 成员函数是指用 const 修饰的成员函数,const 放在参数列表后面,实际修饰的是隐含的this指针,表明在该函数中不能修改类的任何成员。

// const成员函数示例 void Print() const // 实际为void Print(const Date* const this) { cout << _year << "-" << _month << "-" << _day << endl; }

取地址运算符重载示例

class Date { public : // 普通取地址运算符重载 Date* operator&() { return this; // return nullptr; // 可以自定义返回值 } // const取地址运算符重载 const Date* operator&()const { return this; // return nullptr; // 可以自定义返回值 } private : int _year; // 年 int _month; // 月 int _day; // 日 };

Read more

深挖 DeepSeek 隐藏玩法·智能炼金术2.0版本

深挖 DeepSeek 隐藏玩法·智能炼金术2.0版本

前引:屏幕前的你还在AI智能搜索框这样搜索吗?“这道题怎么写”“苹果为什么红”“怎么不被发现翘课” ,。看到此篇文章的小伙伴们!请准备好你的思维魔杖,开启【霍格沃茨模式】,看我如何更新秘密的【知识炼金术】,我们一起来解锁更加刺激的剧情!友情提醒:《《《前方高能》》》 目录 在哪使用DeepSeek 如何对提需求  隐藏玩法总结 几个高阶提示词 职场打工人 自媒体创作 电商实战 程序员开挂 非适用场地 “服务器繁忙”如何解决 (1)硅基流动平台 (2)Chatbox + API集成方案 (3)各大云平台 搭建个人知识库 前置准备 下载安装AnythingLLM 选择DeepSeek作为AI提供商 创作工作区 导入文档 编辑  编辑 小编寄语 ——————————————————————————————————————————— 在哪使用DeepSeek 我们解锁剧情前,肯定要知道在哪用DeepSeek!咯,为了照顾一些萌新朋友,它的下载方式我放在下面了,拿走不谢!  (1)

By Ne0inhk
【AI大模型】DeepSeek + 通义万相高效制作AI视频实战详解

【AI大模型】DeepSeek + 通义万相高效制作AI视频实战详解

目录 一、前言 二、AI视频概述 2.1 什么是AI视频 2.2 AI视频核心特点 2.3 AI视频应用场景 三、通义万相介绍 3.1 通义万相概述 3.1.1 什么是通义万相 3.2 通义万相核心特点 3.3 通义万相技术特点 3.4 通义万相应用场景 四、DeepSeek + 通义万相制作AI视频流程 4.1 DeepSeek + 通义万相制作视频优势 4.1.1 DeepSeek 优势 4.1.2 通义万相视频生成优势 4.2

By Ne0inhk
【DeepSeek微调实践】DeepSeek-R1大模型基于MS-Swift框架部署/推理/微调实践大全

【DeepSeek微调实践】DeepSeek-R1大模型基于MS-Swift框架部署/推理/微调实践大全

系列篇章💥 No.文章01【DeepSeek应用实践】DeepSeek接入Word、WPS方法详解:无需代码,轻松实现智能办公助手功能02【DeepSeek应用实践】通义灵码 + DeepSeek:AI 编程助手的实战指南03【DeepSeek应用实践】Cline集成DeepSeek:开源AI编程助手,终端与Web开发的超强助力04【DeepSeek开发入门】DeepSeek API 开发初体验05【DeepSeek开发入门】DeepSeek API高级开发指南(推理与多轮对话机器人实践)06【DeepSeek开发入门】Function Calling 函数功能应用实战指南07【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:本地部署与API服务快速上手08【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:Web聊天机器人部署指南09【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:基于vLLM 搭建高性能推理服务器10【DeepSeek部署实战】基于Ollama快速部署Dee

By Ne0inhk

DeepSeek各版本说明与优缺点分析_deepseek各版本区别

DeepSeek各版本说明与优缺点分析 DeepSeek是最近人工智能领域备受瞩目的一个语言模型系列,其在不同版本的发布过程中,逐步加强了对多种任务的处理能力。本文将详细介绍DeepSeek的各版本,从版本的发布时间、特点、优势以及不足之处,为广大AI技术爱好者和开发者提供一份参考指南。 1. DeepSeek-V1:起步与编码强劲 DeepSeek-V1是DeepSeek的起步版本,这里不过多赘述,主要分析它的优缺点。 发布时间: 2024年1月 特点: DeepSeek-V1是DeepSeek系列的首个版本,预训练于2TB的标记数据,主打自然语言处理和编码任务。它支持多种编程语言,具有强大的编码能力,适合程序开发人员和技术研究人员使用。 优势: * 强大编码能力:支持多种编程语言,能够理解和生成代码,适合开发者进行自动化代码生成与调试。 * 高上下文窗口:支持高达128K标记的上下文窗口,能够处理较为复杂的文本理解和生成任务。 缺点: * 多模态能力有限:该版本主要集中在文本处理上,缺少对图像、语音等多模态任务的支持。 * 推理能力较弱:尽管在自然语言

By Ne0inhk