当前位置: 首页 > news >正文

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. 构造函数可以使用默认参数减少重载数量

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


http://www.jsqmd.com/news/364797/

相关文章:

  • FPGA神经网络功耗稳定性监控的优化策略与实战指南
  • 流数据测试:LSTM-Kafka在消息积压阈值预测的监控插件‌
  • 从零理解卷积神经网络(CNN):比全连接强在哪?
  • 对象和类(类的构造函数和析构函数)
  • 卷积神经网络(整体结构)
  • 颠覆性技术变革:AI驱动无代码测试新范式
  • 【prompt】- mcp开发专家
  • 轮廓线 插头 DP
  • PostgreSQL复制的监控
  • C++变量的基础使用
  • 【完整源码+数据集+部署教程】交通标线车道线分割系统源码&数据集分享 [yolov8-seg-C2f-EMSC&yolov8-seg-SPPF-LSKA等50+全套改进创新点发刊_一键训练教程_We
  • IoT电子价签:打造智能化商超秋冬新品促销新体验 - 指南
  • pc(mac/win)端app 能基于webkit 打包发布
  • 【完整源码+数据集+部署教程】航拍区域图像分割系统源码&数据集分享 [yolov8-seg-C2f-DAttention&yolov8-seg-HGNetV2等50+全套改进创新点发刊_一键训练教程
  • 【完整源码+数据集+部署教程】工图机械零件特征图像分割系统源码&数据集分享 [yolov8-seg-LAWDS&yolov8-seg-RevCol等50+全套改进创新点发刊_一键训练教程_Web前端
  • 洛谷 P1160:队列安排 ← 数组模拟
  • 小白版详解:剪枝怎么评好坏?怎么判断该剪谁?
  • 2026年北京VIP陪诊公司权威测评,高品质服务机构精选 - 品牌鉴赏师
  • 三种剪枝算法流程
  • 【含文档+PPT+源码】基于微信小程序的驾考在线学习与测试系统的设计与实现
  • 2026.02.10
  • 【Matlab】MATLAB 图形标注教程:title、xlabel、ylabel 用法详解与实战
  • 小鼠CD185抗体如何助力CXCR5靶向ADC药物的研发与机制探索?
  • Node.js 编程实战:路径模块(path)详解 - 教程
  • 一文读懂分辨率:从概念到硬件应用,解锁视觉体验新高度 - 详解
  • 2026年布袋除尘器厂商推荐:不锈钢脉冲式布袋除尘器厂家哪家靠谱 - 栗子测评
  • ollydbg脚本学习
  • Java 算法
  • 4022:【GESP2309五级】巧夺大奖
  • 什么是强连通图