news 2026/3/6 0:07:55

C++构造函数与析构函数:对象生命周期的守护者

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++构造函数与析构函数:对象生命周期的守护者

C++构造函数与析构函数:对象生命周期的守护者

引言:为什么需要特殊的初始化函数?

在C++中,我们希望使用类对象就像使用基本类型一样方便。比如,我们可以这样初始化一个整数或结构体:

intyear=2001;structthing{char*pn;intm;};thing amabob={"wodget",-23};

但为什么不能这样初始化Stock对象呢?

Stock hot={"Sukie Autos, Inc.",200,50.25};// 错误!

原因在于数据封装:类成员通常是私有的,不能直接从外部访问。我们需要一种特殊的方法来初始化对象,这就是构造函数的用武之地。

构造函数:对象的"出生证明"

什么是构造函数?

构造函数是一种特殊的成员函数,在创建对象时自动调用。它的名称与类名相同,没有返回类型(连void都不是)。

声明和定义构造函数

让我们为Stock类添加构造函数:

// 构造函数原型Stock(conststd::string&co,longn=0,doublepr=0.0);// 构造函数定义Stock::Stock(conststd::string&co,longn,doublepr){company=co;if(n<0){std::cerr<<"Number of shares can't be negative; "<<company<<" shares set to 0.\n";shares=0;}else{shares=n;}share_val=pr;set_tot();// 计算总价值}

使用构造函数的两种方式

显式调用:

Stock food=Stock("World Cabbage",250,1.25);

隐式调用:

Stockgarment("Furry Mason",50,2.5);

与new一起使用:

Stock*pstock=newStock("Electroshock Games",18,19.0);

默认构造函数:对象的"默认设置"

默认构造函数是在未提供初始值时使用的构造函数。例如:

Stock fluffy_the_cat;// 使用默认构造函数

重要原则:

  • 如果没有定义任何构造函数,编译器会自动生成一个不做任何事的默认构造函数
  • 但如果定义了任何构造函数,就必须手动提供默认构造函数

定义默认构造函数的两种方法:

  1. 为已有构造函数的参数提供默认值:
Stock(conststd::string&co="Error",intn=0,doublepr=0.0);
  1. 重载一个无参数的构造函数:
Stock();// 默认构造函数

推荐做法:始终提供对类成员做隐式初始化的默认构造函数。

析构函数:对象的"临终关怀"

当对象生命周期结束时,析构函数自动被调用,用于清理资源。

定义析构函数

析构函数名为~类名,没有参数和返回类型:

// 析构函数原型~Stock();// 析构函数定义Stock::~Stock(){std::cout<<"Bye, "<<company<<"!\n";}

何时调用析构函数?

  • 静态对象:程序结束时
  • 自动对象:离开其作用域时
  • 动态对象:使用delete释放内存时
  • 临时对象:结束使用时

完整示例:改进的Stock类

头文件 (stock10.h)

#ifndefSTOCK10_H_#defineSTOCK10_H_#include<string>classStock{private:std::string company;longshares;doubleshare_val;doubletotal_val;voidset_tot(){total_val=shares*share_val;}public:Stock();// 默认构造函数Stock(conststd::string&co,longn=0,doublepr=0.0);~Stock();// 析构函数voidbuy(longnum,doubleprice);voidsell(longnum,doubleprice);voidupdate(doubleprice);voidshow()const;// const成员函数};#endif

实现文件 (stock10.cpp)

#include<iostream>#include"stock10.h"// 默认构造函数Stock::Stock(){std::cout<<"Default constructor called\n";company="no name";shares=0;share_val=0.0;total_val=0.0;}// 带参数的构造函数Stock::Stock(conststd::string&co,longn,doublepr){std::cout<<"Constructor using "<<co<<" called\n";company=co;if(n<0){std::cout<<"Number of shares can't be negative; "<<company<<" shares set to 0.\n";shares=0;}else{shares=n;}share_val=pr;set_tot();}// 析构函数Stock::~Stock(){std::cout<<"Bye, "<<company<<"!\n";}// 其他成员函数实现...

使用示例 (usestock2.cpp)

#include<iostream>#include"stock10.h"intmain(){{usingstd::cout;cout<<"Using constructors to create new objects\n";Stockstock1("NanoSmart",12,20.0);// 隐式调用stock1.show();Stock stock2=Stock("Boffo Objects",2,2.0);// 显式调用stock2.show();cout<<"Assigning stock1 to stock2:\n";stock2=stock1;cout<<"Using a constructor to reset an object\n";stock1=Stock("Nifty Foods",10,50.0);// 创建临时对象并赋值stock1.show();cout<<"Done\n";}// 离开作用域,析构函数被调用return0;}

C++11新特性:列表初始化

C++11允许使用列表初始化语法初始化对象:

// 匹配带参数的构造函数Stock hot_tip={"Derivatives Plus Plus",100,45.0};Stock jock{"Sport Age Storage, Inc"};// 使用默认参数Stock temp{};// 默认构造函数

const成员函数:承诺不修改对象

对于const对象,只能调用不会修改对象状态的成员函数:

constStock land=Stock("Kludgehorn Properties");land.show();// 需要show()是const成员函数

如何声明const成员函数?

// 声明voidshow()const;// 定义voidStock::show()const{// 不能修改任何成员变量std::cout<<"Company: "<<company<<"\n";}

最佳实践:只要成员函数不修改对象,就应将其声明为const。

构造函数和析构函数总结表

特性构造函数析构函数
名称与类名相同~类名
返回类型
参数可以有(可重载)
调用时机创建对象时销毁对象时
主要用途初始化对象清理资源
默认版本无自定义构造函数时自动生成始终自动生成(可自定义)

构造函数使用技巧

单参数构造函数的隐式转换:

Bozo dribble=44;// 隐式调用Bozo(44)

避免隐式转换(C++11):

explicitBozo(intn);// 禁止隐式转换

关键要点

  1. 构造函数是对象的"出生证明",负责初始化工作
  2. 析构函数是对象的"临终关怀",负责清理工作
  3. 如果定义了任何构造函数,必须手动提供默认构造函数
  4. 使用const成员函数保证不修改对象状态
  5. C++11的列表初始化让对象创建更简洁
  6. 构造函数可以使用默认参数减少重载数量

记住:良好的类设计应该让对象"生得正确,死得干净"。构造函数和析构函数正是实现这一目标的关键工具!


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/3 18:09:18

【完整源码+数据集+部署教程】交通标线车道线分割系统源码&数据集分享 [yolov8-seg-C2f-EMSC&yolov8-seg-SPPF-LSKA等50+全套改进创新点发刊_一键训练教程_We

背景意义 随着城市化进程的加快&#xff0c;交通管理面临着日益严峻的挑战。交通标线作为道路交通管理的重要组成部分&#xff0c;不仅为驾驶员提供了行驶指引&#xff0c;还在交通安全中发挥着不可或缺的作用。传统的交通标线检测方法多依赖于人工标注和规则识别&#xff0c;效…

作者头像 李华
网站建设 2026/3/3 17:47:34

4022:【GESP2309五级】巧夺大奖

【题目描述】小明参加了一个巧夺大奖的游戏节目。主持人宣布了游戏规则&#xff1a;1、游戏分为n 个时间段&#xff0c;参加者每个时间段可以选择一个小游戏。2、游戏中共有n 个小游戏可供选择。3、每个小游戏有规定的时限和奖励。对于第i 个小游戏&#xff0c;参加者必须在第T…

作者头像 李华
网站建设 2026/3/3 17:57:26

2016-2025年地级市绿色数字中心政策数据DID

数据简介 绿色数字中心&#xff0c;是新一代致力于实现可持续发展的信息基础设施。它聚焦于能源效率的深度优化、环境影响的显著降低&#xff0c;以及资源循环利用水平的大幅提升。为达成这一目标&#xff0c;采取多维度协同推进的策略&#xff1a;积极推动技术创新&#xff0…

作者头像 李华
网站建设 2026/3/3 17:49:18

单例(静态代码块饿汉式)

实现优缺点说明 这种方式和静态常量的方式类似&#xff0c;只不过将类实例化的过程放在了静态代码块中&#xff0c;也是在类装载的时候&#xff0c;就执行静态代码块中的代码&#xff0c;初始化类的实例 结论&#xff1a;这种单例模式可用&#xff0c;但是可能造成内存浪费

作者头像 李华
网站建设 2026/3/3 18:18:27

不同应用场景下,LoRaWAN 室内与室外网关的正确选择方式

在搭建 LoRaWAN 网络时&#xff0c;很多人第一步就卡住了&#xff1a; 到底该选室内网关&#xff0c;还是室外网关&#xff1f; 参数看起来差不多&#xff0c;价格却差不少&#xff1b; 都说能覆盖&#xff0c;实际效果却天差地别。 这篇文章&#xff0c;我们不讲复杂理论&am…

作者头像 李华
网站建设 2026/3/5 6:12:33

【观察】联想数据网络训推一体解决方案:三位一体,铸就“全能ACE”

当前&#xff0c;我们正处于人工智能技术变革的关键历史节点。在这场浪潮中&#xff0c;如何准确把握技术趋势&#xff0c;将AI深度融合到行业实际场景中&#xff0c;以更高效率、更低成本、更广覆盖的方式赋能行业的智能化转型&#xff0c;已成为全社会关注的焦点。在此背景下…

作者头像 李华