由始至终----构造与析构

【HarmonyOS实战开发】鸿蒙设计模式-单例模式 这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。 阅读详情

由始至终

                         ----构造与析构

作者:HolyFire

我们在平时的生活中一般会总结出一些规律,早上起床会刷牙洗脸,晚上会洗澡睡觉,这些都成了惯例。使用瓶装调味品时先将瓶盖打开,用完后将瓶盖盖上。这是一种好习惯。但是有些人不同,他们往往偷懒,一个常常不刷牙不洗脸不洗澡的人会有体味,东西放得乱七八糟的人生房间很不整洁。这些都是我们不希望看到的。当然编程中我们也不希望代码乱七八糟。

使用一个未初始化的变量简直就是灾难,使用一个未初始化的指针将导致崩溃。这是我的忠告。在C++中初始化不会有附加的效果,不会降低效率,我们要做的是养成好习惯,产生一个对象的时候就将它初始化。

对于

Object.Init();

Object.Free();

这样的调用并不是很困难,要记住他也不是难事,但是谁都不能保证他永远不会忘记,更糟糕的是

Object.Init();

Object.Free();

没有配对使用

Object.Init();

Object.Free();

Object.Free();

或

Object.Init();

Object.Init();

Object.Free();

会带来什么样的结果,谁也不知道,而且这样的错误,编译器不会报错。这是多么可怕的错误,一个程序员最怕遇上的就是这样的逻辑错误,它可能为了找这样的一个错误花上一整天时间。

让我们看看有什么好的办法。

一个对象按时间来分析,一般有三个阶段,出生,活动,死亡。与我们要做的有什么相关之处呢,初始化,运行,释放。很好,对照一下,我们发现在对象出生的时候初始化,死亡的时候释放,如果这一切能用这样的机制来操作,我们就再也不用担心会由于忘记或错误的使用带来麻烦了。

C++里就提供了这样的机制。使用他有个约定

class Object{

public:

       Object();   //与类同名的函数,该函数没有返回值,叫做构造函数

~Object();  //类似的,在构造函数名前加一个取反符号,叫做析构函数

};

构造函数将在对象产生的时候调用

析构函数将在对象销毁的时候调用

调用的过程和实现方法由编译器完成,我们只要记住他们调用的时间就行了,而且他们的调用是自动完成的,不需要我们控制。

#include <iostream>

using namespace std;

class Object{

public:

       Object(){ cout << "Object ON!" << endl; }

       ~Object(){ cout << "Object OFF!" << endl; }

};

void main()

{

       Object o;

}

运行结果

Object ON!

Object OFF!

构在函数和析构函数确实的执行了

现在我们来一个应用的例子

一个字符串类,它需要保存字符串的内容,但是它不知道字符串的大小,那么设计这个字符串类的时候,保存字符串的成员变量就不能用固定大小的数组,而是用可以间接操作数组的指针。

#include <iostream>

#include <string.h>

using namespace std;

class string{

private:

       char * data;

public:

       string(){ data = NULL; }

       string( char * str )

              {

              cout << "Copy string: " << str << endl;

              data = new char[ strlen(str) + 1 ];

              memcpy( data , str , strlen(str) + 1 );

              }

       char * Data(){ return data; }

       ~string()

              {

              if( data )

                     {

                     cout << "Free string: " << data << endl;

                     delete data;

                     }

              }

};

void main()

{

       {

string s("abcd");

       cout <<"Show String: " << s.Data() <<endl;

}

cin.get();

}

Copy string: abcd   //执行了string::string( char * str ) 构造函数

Show String: abcd

Free string: abcd       //由于在{}中产成的对象是临时对象,它的生命期在}后就结束了,所以string::~string() 析构函数被调用

申请内存和释放内存的操作自动完成了,构造函数和析构函数的目的在于一个类可以象普通类型一样初始化和释放,从而保证了封装。

上面的例子有两个构造函数,这么什么大不了的,我们看过《面面俱到----重载》得都知道,重载的把戏。

要注意的是构造函数可以有参数,在继承中如何处理呢。

class mystring : public string{

public:

       mystring( char * str ):string( str ){ }

}

mystring( char * str ):string( str )

记住这样的形式,给自己的父类传递函数就用这样的书写格式,这是一个约定。

构造函数后面加上一个:表示后面是一个初始化序列,说它是一个序列是因为它可以初始化多个成员变量,在初始化序列里调用向父类传递参数是为了保证类的产生的顺序,先产生父类,然后是子类。使用初始化有个好处就是可以提高效率。

string(){ data = NULL; }

可以改写成

string():data(NULL){ }

他的作用是产生成员变量char * data时将他的值置为NULL。从而少了data = NULL;这步操作。

注意,这里构造和析构有一个顺序问题,就是构造时应该从基类开始按继承的层次顺序调用,析构的时候顺序正好相反。这样处理是因为,子类可能在构造函数里使用父类的成员变量,如果父类还没有创建,那就会有问题,而析构的时候,如果父类先析构,也会有这样的问题。

析构函数还有一个能否正确运行的问题。

#include <iostream>

using namespace std;

class One{

public:

       One(){ cout << "One ON!" << endl; }

       ~One(){ cout << "One OFF!" << endl; }

};

class Two : public One{

public:

       Two(){ cout << "Two ON!" << endl; }

       ~Two(){ cout << "Two OFF!" << endl; }

};

class Three : public Two{

public:

       Three(){ cout << "Three ON!" << endl; }

       ~Three(){ cout << "Three OFF!" << endl; }

};

void main()

{

       Three three;

}

运行结果

One ON!

Two ON!

Three ON!

Three OFF!

Two OFF!

One OFF!

正确

void main()

{

       Three * three = new Three;

        delete three;

}

运行结果

One ON!

Two ON!

Three ON!

Three OFF!

Two OFF!

One OFF!

正确

void main()

{

       One * three = new Three;

        delete three;

}

运行结果

One ON!

Two ON!

Three ON!

One OFF!

不好了,Two和Three的析构都没有运行,怎么会这样,原来One * three指出了指针指向的是一个One类的对象。如何得到正确的结果呢,如果能让One类记住被继承后的变化就好了。

对了!虚函数,在《后入为主----虚函数》中可以知道,虚函数有这个特性,不信试试看。

class One{

public:

       One(){ cout << "One ON!" << endl; }

       virtual ~One(){ cout << "One OFF!" << endl; }

};

void main()

{

       One * three = new Three;

        delete three;

}

运行结果

One ON!

Two ON!

Three ON!

Three OFF!

Two OFF!

One OFF!

正确

这个特点很重要,我们要牢牢记住,我们称这种方法为“虚析构”,在多态里运用非常广泛,也是编写可复用代码的一个重要技巧。

构造和析构的作用机制就是自动化,简化编程的复杂度。还有要记住的是,在一个类的构造函数里分配了的资源尽量要记得在该类的析构函数里释放,当然也允许提前释放,你可以在析构函数里判断它是否已经释放,如果没有就释放。这就是----由始至终,它间接的描述了一个对象的生和死(记住这一点很重要,因为我以后会讲到如何运用这个特性控制对象的生死)。

2001/8/23

丁宁

Java小游戏制作总结 子弹移动的默认 在代码中,如果人物初始状态静止没有方向,子弹同样是静止的状态 如何去解决这个BUG,很简单,在人物的方向中,我们设置一个字符串的 变量去获取人物方向上下左右的值,同时给他赋予一个初始的方向值,在传 给子弹的方向中,使其拥有默认属性的同时还能根据人物的变动进行相应的 方向改变 优化代码—继承 这些对象里面有很多共有的属性,可以直接赋值给子类,减少代码量 使得这些代码变得简洁易懂 总结 一,首先分析 分析对象,寻找属性,发现方法 难点分析 记录难点 二,插入图片 首先调用一个 阅读详情

相关推荐

【电路设计】带阻滤波器实战:从理论到Twin-T陷波电路实现

本文详细介绍了带阻滤波器的原理与Twin-T陷波电路的实战应用,从基础概念到工程实现全面解析。通过具体案例展示如何设计高Q值滤波器,解决电源噪声等实际问题,并分享PCB布局和元件选型的实用技巧,助力工程师提升电路设计能力。

gg901的博客 1011

由始至终----构造与析构 (转)

由始至终----构造与析构 (转)[@more@]由始至终 ----构造与析构XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" ...

cuiji1279的博客 148

六维力传感器选型指南:电阻式vs电容式,哪个更适合你的工业场景?

本文深入解析六维力传感器在工业自动化中的选型要点,重点对比电阻式与电容式传感器的核心原理、环境适应性及成本结构。针对不同工业场景(如高精度装配、重载机器人等),提供专业选型建议,帮助工程师优化系统性能与经济效益。

weixin_42525005的博客 395

女娲造人----构造析构与对象的生死

女娲造人                                                ----构造析构与对象的生死作者:HolyFire 在《由始至终----构造与析构》最后我提到了C++中的构造函数和析构函数与对象的生和死有着很大的关系,好好运用还能控制对象的生死,使得编程的思路更接近现实世界的规律。 我们先回忆一下,在对象创建的时候,合适的构造函数将被

Apollo_HolyFire的专栏 1629

电力-平衡式IEC 60870-5-101规约报文解析

本文详细介绍了电力自动化中平衡式IEC 60870-5-101规约的应用,包括链路建立与初始化、对时、遥控操作、数据上送和总召唤等关键步骤,通过实例解析了报文格式和交互过程,是理解配网自动化通信的重要参考资料。

让你爱上电路设计 5684

小白的MatSWMM使用心路(二)——用matlab修改INP文件参数/使用matlab查找txt内容并修改多行内容

说是修改inp,但是里面的内容大部分还是讲怎么修改txt的……(?)。包含如何找到需要的参数(关键字)位置,以及修改那个位置的txt这样的内容。希望能帮助大家吧……Matlab你要多出好用的功能啊!

weixin_44276743的博客 4530

温故知新----再谈构造函数

温故知新                   ----再谈构造函数作者:HolyFire如果不知道构造函数的请先看一下《由始至终----构造与析构》,看过的我就不再多言,直接转入话题。定义一个类的的实例的时候,可以看到这样的形式classA a;        //构造函数不需要参数不需要参数的构造函数称之为缺省构造函数。不需要参数有两种情况1:构造函数没有参数

Apollo_HolyFire的专栏 1362

DA14531之搭建开发环境

DA14531之搭建开发环境

hejinwu1314的博客 1777

温故知新----再谈构造函数 (转)

温故知新----再谈构造函数 (转)[@more@]温故知新 ----再谈构造函数XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office"...

csd3176的博客 232

SAP-ABAP:SAP采购业务核心表关联关系详解

MM(核心)、FI(财务)、SD(计划协议):PR → PO → GR → MIRO → FI过账。

baidu_35680696的博客 930

PyTorch 面试题及详细答案120题(54-70)-- 模型训练与评估

本文介绍了PyTorch模型训练的基本流程和核心概念。主要内容包括: 模型训练基本流程:通过代码示例展示了数据准备、模型定义、损失函数和优化器选择、训练循环(前向传播、反向传播、参数更新)的完整过程,并包含验证集评估的实现。 训练过程中的关键概念: Epoch:完整遍历一次训练集 Batch:将数据分成小批次 Iteration:一个Batch的参数更新过程 三者关系:1 Epoch = N/B Batch = N/B Iteration(N为样本数,B为batch_size) PyTorch数据加载机制:

大剑师兰特的GIS世界 489

js中原型链的理解

js原型链的理解 由于原型链涉及构造函数、函数Function、引用类型Object及特定的两个属性prototype和_proto_,因此在谈原型链前先搞清楚他们之间的关系; 1、函数必然有prototype和_proto_两个属性,所有的函数(包括自定义函数)都是Function实例的对象; 2、对象必然有_proto_属性,但不一定有prototype;实例的对象通过_proto_属性连接...

weixin_43735593的博客 1万+

微信小程序 - 接入腾讯地图 SDK 及详细使用教程,结合小程序 mpa 地图组件展示腾讯地图(基础使用 / 授权当前位置 / 配合小程序map组件的使用 / 腾讯地图逆地址解析 / 坐标系的转化)

微信小程序使用腾讯地图完整流程,微信小程序 接入腾讯地图,如何在微信小程序中接入腾讯地图,微信小程序引入腾讯地图API方法,腾讯地图小程序SDK,微信小程序实现使用腾讯地图SDK步骤详细介绍,微信小程序接入腾讯地图(线路规划、逆解析)、高德地图,微信小程序之使用腾讯地图,微信小程序 接入第三方地图,小程序服务器配置地图,微信小程序接入腾讯地图,微信小程序插入腾讯地图教程,微信小程序如何调用腾讯地图,如何在微信小程序中接入腾讯地图,微信小程序腾讯地图SDK使用方法,在微信小程序上创建一个简单的腾讯地图,微信小

✅ 精选推荐文章 1万+

面向对象编程基础

类

谎言的舞蹈的博客 226

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

软件工程

 从商业角度分析J2EE与WINDOWS DNA体系结构(点击:2269)(2001-11-16 00:00:00)      这份白皮书的以下部分要讨论: 与COM+、WINDOWS DNA相比较,使用EJB、J2EE所能带来的商业好处。 1 业界支持 温故知新----再谈构造函数(点击:2898)(2001-0

1358

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

java中的静态代码块

在类的成员方法之外,用static修饰代码区域可以称之为静态代码块。定义一块静态代码块,可以完成类的初始化操作,在类的声明时就会运行。 语法如下: public class StaticTest{ static{ //执行语句 } } 以下示例为说明静态代码块、非静态代码块、构造方法、成员方法的调用顺序 public class StaticTest{ static String name;...

爱学习的1024 232

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

原型与原型链

原型与原型链

qq_60976312的博客 931

【ssm入门#5-Spring5】IOC控制反转降低耦合核心思想:工厂模式配置文件解耦+ApplicationContext找不到getBean()方法+bean标签和管理对象细节+依赖注入各数据类型

本文基于下述教程编写:【B站】ssm教程 工厂模式解耦思想 简单应用,实现业务层和持久层解耦: public class BeanFactory { //加载配置文件操作类 private static Properties props = null; //存放已经生成好的实例对象的容器 private static Map<String, Object> beans = null; static { try {

Jelly_Bean的博客 303

关于Servlet的生命周期

关于Servlet的生命周期 以下我们写一个一个html,和一个简单的Servlet,然后在html页面上以dopost方式来提交表单来访问Servlet的dopost函数,然后分析Servlet的生命周期   这个工程的名字: TestLifeCyecleServlet index.html: This is my JSP page.

irelandken的专栏 3201

Java——静态代码块

语法: public class StaticTest { static { //此处编辑执行语句 } } 实例:代码块的执行语句 public class StaticTest { static String name; // 静态代码块 static { System.out.println(name + "静态代码块"); } // 非静态代码块 { System.out.println(name + "非静态代码块"); } public S

qq_44962061的博客 368

java基础进阶(一)——创建和销毁对象

这系列由笔者在读《Effective Java》时做的一些笔记和提醒自己的思考方法(其中有些术语是参照书的): (一)用静态工厂方法代替构造器: 静态工厂方法是类提供的一个返回类的实例的静态方法。 优势: 1.具有名称,它不像构造器一样用类名,它可以拥有自己的方法签名,这在某些情况下更便于阅读,如类中只能带有一个指定签名的构造器,但当需要多个构造器时,往往会采用改变参数顺序的方式,

A870251703的博客 634

static静态

** 静态变量 ** 共享变量用static修饰,该变量就是静态变量。 public class StaticDemo { static int x; int y; public StaticDemo(int x, int y) { this.x = x; this.y = y; } public static void main(String[] args) { StaticDemo a = new StaticDemo(1, 2); StaticDemo b = new S

lijiang_shen的博客 284

单例模式详解(懒汉式、饿汉式、线程安全、双重检验锁)

单例模式详解(懒汉式、饿汉式、线程安全、双重检验锁) 单例(Singleton)概述 使单例模式是为了:保证一个类只有一个实例,并且提供这个实例的全局访问点 一般做法是把该单例实例作为该类的一个静态变量、构造方法私有化,至于如何取得和创建该对象,有两种种方法实现:懒汉式和饿汉式 Ⅰ 懒汉式-线程不安全 这个实现在多线程环境下是不安全的,如果多个线程能够同时进入 if (uniqueInstance...

weixin_43217564的博客 3555

Android异步通信——HandlerThread源码解析

前面已经说过,每一个线程的ThreadLocal都保存了一个looper对象,这个looper对象只存在于安卓之中,通过这个looper,会不断地从消息队列中进行轮训,当有消息到达的时候,就会取出消息,进行处理。构造函数Handler正是结合了线程Thread以及Handler,大体上定义了一个线程,并且在启动线程时创建Looper,我们先来看看它的构造函数//线程优先级默认为Process.THR

u012241729的专栏 458

从动图开始,带你研究什么是三级缓存

1、三级缓存各自的作用第一级缓存存的是对外暴露的对象,也就是我们应用需要用到的第二级缓存的作用是为了处理循环依赖的对象创建问题,里面存的是半成品对象或半成品对象的代理对象第三级缓存的作用处理存在 AOP + 循环依赖的对象创建问题,能将代理对象提前创建2、Spring 为什么要引入第三级缓存严格来讲,第三级缓存并非缺它不可,因为可以提前创建代理对象提前创建代理对象只是会节省那么一丢丢内存空间,并不会带来性能上的提升,但是会破环 Spring 的设计原则。

2401_83384536的博客 603

Java学习第7天——继承的概念及作用、方法重写、this、super、final的使用

前言 学习了继承的概念及作用、方法重写、this的使用、super的使用 一.继承的概念及作用 1.什么是继承 子类继承父类 2.继承的作用 子类扩展父类的属性以及方法,就是为了实现代码的复用(继承在Java中只能单继承,不能多继承) 3.继承的注意 子类可以继承父类中有权限访问的属性以及方法 所有的引用类型都默认继承了超类Object 二.方法重写 1.什么是方法重写 子类重写父类的方法(子类覆盖父类的方法) 2.方法重写的目的是什么 ...

yinhaoooo的博客 2859
上一篇: 面面俱到----重载
下一篇: 龙生九子----多态
Apollo_HolyFire
博客等级 码龄25年 3粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值