C++自带的古老诅咒

古老的密码 前言 之所以自己写博客,除了总结自己的学习,另外就是发现网上的答案太千篇一律了,大多数人都是直接粘贴复制。 问题描述 古罗马帝国与各部门有一个强有力的政府系统,包括一个秘密服务部门。重要的文件以加密的形式发送防止窃听。在那个时代最流行的密码被称为替代密码置换密码。例如,应用替代密码,改变所有字母“A”到“Y”字母表中的下一个字母(注:“Z”变成“A”),如:“VICTORIOUS”得到... 阅读详情

话说,在大学刚接触C语言时,我们的老师便不断地!不断地!!不断地!!!告诉我们要把main函数分为5个部分:

1、声明+初始化    2、赋值    3、输入    4、输出      5、释放

我就非常不理解,为什么非要把『声明+初始化』以及『赋值』两步分开。
难道『初始化+赋值』一起会遭受诅咒?
明明教材就有程序是这么这样的:int i = 10; 更有甚者,直接int i, j  = 1,k = 10; 连声明加赋值,直接都搞定。
而为什么老曹总逼我们把别人写一行的代码写成10行……

//initialization
int i = 0
int j = 0;
int k = 0;


//assignment
i = 0;
j = 1;
k = 10;

究竟是为什么需要将赋值这一步单独提出来呢?难道是由于这样做才能防止某种特殊的诅咒??对的!
我今天才发现其中包含了VC6.0包括VS2008中包含着这样一个“诅咒”~

首先我们写这样一段简单的代码

class Example
{
private:
int m_data1;
int m_data2;
int * m_pdata3;

public:
Example();
void setData(int given1, int given2, int given3);
};

Example::Example()
{
m_data1 = 0;
m_data2 = 0;
m_pdata3 = new int;
*m_pdata3 = 0;
}

void Example::setData(int given1, int given2, int given3)
{
m_data1 = given1;
m_data2 = given2;
*m_pdata3 = given3;
}


int _tmain(int argc, _TCHAR* argv[])
{
Example e1;

e1.setData(10, 20, 30);

Example e2;

e2 = e1;

e2.setData(40, 50, 60);

return 0;
}

执行是可以通过的。
在这里,我们先定义Example类e1;后定义了Example类e2。我们并没有重载赋值运算符=,然而编译器却找到了一种方法使得 e2 = e1 这个运算符得以实现。那么,可以这么理解,在重载赋值 = 之前,系统默认创建了一个赋值函数。在这里,我们暂且把这个赋值函数叫做:默认赋值函数。

下面我们看一下默认赋值函数的功能。
首先,在e1.setData(10, 20, 30)后,监视到e1是这样的:

当e2 = e1 赋值后,e2的监视窗口如此:


可以看到,e1,e2中包含的指针m_pdata3指向同一片存储空间。如下的操作更能证明这点:
在e2.setData(40, 50, 60),对e2内部数据进行修改时,会发现e1内部指针对应的内存也进行了改变,变成了60



由此,我们可以推断,默认赋值函数的功能如下:将赋值符右边类的成员变量的取值原封不动得赋给左边的类内同样的成员变量。

既然清楚了,赋值运算符具有默认赋值函数。
下面我们手工给Example类重载赋值函数。
Example& Example::operator=(const Example& e)
{
m_data1 = e.m_data1;
m_data2 = e.m_data2;
m_pdata3 = new int;
*m_pdata3 = *(e.m_pdata3);

return *this;
}

当然,我们不希望改动e2指针内的数据,e1发生同样变化。换言之本类对象开辟的空间,归此类对象独有。因此,在重载时,开辟了空间后,将上一个空间中的值赋给新空间。
主函数不变:
int _tmain(int argc, _TCHAR* argv[])
{
Example e1;

e1.setData(10, 20, 30);

Example e2;

e2 = e1;

e2.setData(40, 50, 60);

return 0;
}

当执行完毕e2.setData(40, 50, 60)后,通过监视窗口,我们会发现:

果然,e2的开辟的空间变成了60,而e1没有变化。目的实现。


好了,有了这些储备,相信你会很容易理解这个“诅咒”了:
当你把刚刚主函数的两句
Example e2;          //初始化

e2 = e1;               //赋值
中的赋值与初始化合二为一,即写成Example e2 = e1后
主函数成为这样:
int _tmain(int argc, _TCHAR* argv[])
{
Example e1;

e1.setData(10, 20, 30);

Example e2 = e1;

e2.setData(40, 50, 60);

return 0;
}

让我们看看程序执行结果:

我们会发现,e2没有独立开辟空间,而是指向了e1的空间。
原来赋值与初始化合一时,调用的 = 运算符时,执行的不是重载的 = 运算符函数,而是默认赋值函数!


这就是那个将初始化与赋值合二为一的诅咒啊!不加区分也许有一天就会造成意想不到的问题!



写到最后,正式感谢我的编程经验丰富的C语言老师老曹。听这些内行人的忠告,会走很少弯路的。

C++写的Windows下遍历文件列表程序,处理全程使用UTF16 记得以前看过别人用MFC写的遍历文件夹列表的程序,用CFileDialog类中的GetNextPathName()函数可以轻易地时间文件遍历。 然而MFC太老了,调用起来又麻烦,还得用动态链接。 CLR的Directory类File类,感觉自己不太熟,总觉得写完了,没有移植的可能。 所以我最近用Windows函数写了一个程序,实现遍历文件夹,在内存中形成链式的文件夹内部所有 阅读详情

相关推荐

Ansys Lumerical | 薄膜铌酸锂电光调制器的仿真与优化

本文详细介绍了使用Ansys Lumerical进行薄膜铌酸锂电光调制器仿真与优化的全流程。从基础原理到电学仿真、光学模拟技巧,再到设计优化实战经验,帮助工程师掌握这一先进光电器件的仿真方法。重点解析了薄膜铌酸锂的Pockels效应Mach-Zehnder结构设计,并提供了常见问题排查指南最新发展动态。

vulkan6gpu的博客 1142

《代码之丑》学习笔记10——变量声明赋值分离:普通的变量声明,怎么也有坏味道?

10 | 变量声明赋值分离:普通的变量声明,怎么也有坏味道? 诚然,变量声明是写程序不可或缺的一部分,我并不打算让你戒掉变量声明,严格地说,我们是要把变量初始化这件事做好。 1. 变量的初始化 我们先来看一段代码: EpubStatus status = null; CreateEpubResponse response = createEpub(request); if (response.getCode() == 201) { status = EpubStatus.CREATED; } else

大白的成长之路 452

华为OD机试2025A卷 - 分苹果(Java & Python& JS & C++ & C )

华为OD机试2025A卷 - 分苹果(Java & Python& JS & C++ & C )

算法大师! 681

数组声明赋值分开出现异常

Could not convert ‘{0, 0, 0}’ from ‘<brace-enclosed initializer list>’ to ‘std::array<unsigned int 因为在头文件中声明了 int *a 但是在构造函数中赋值出现如上错误 很多人建议 添加-std =c++11,但是无效 ...

分享嵌入式,移动端,智能应用,数据库等专业板块,记录知识碎片!!! 2431

Qt专家、订阅号“程序视界”创建者安晓辉:引导你逐步深入学习C++

作者简介:安晓辉,程序员、技术管理者、作家、职业规划师、在行行家、分答答主,著有《Qt on Android 核心编程》、《Qt Quick核心编程》《你好哇,程序员》,创建订阅号“程序视界”。 C++是一门古老而复杂的语言,绝不是一门可以速成的语言,学习它需要有意识的刻意练习长时间的持续不断的磨练。而大多数人不太能耐得住寂寞,喜欢速成,所以像《21天学通C++》这种书就比较受欢迎,卖得...

小秋博客 1024

古老而经典的话题--图书管理系统 C++语言实现

/*****************************************************************************************/#include #include #include #include //输入/输出文件流类using namespace std;const int Maxr=100;//最多的读者const int Maxb=1

程序的江湖?! 勿在浮砂筑高台! 5143

FILM帧插值技术:如何让静态照片动起来?[特殊字符]

想让你的静态照片变成流畅的慢动作视频吗?FILM帧插值技术正是你需要的魔法工具!✨ 这个由谷歌研究团队开发的开源项目,专门解决大范围运动场景下的视频帧间插补问题,让照片动起来不再是梦想。💡 ## 🎯 项目亮点:为什么选择FILM? **一句话亮点**:FILM能将近乎相同的照片转换成看起来像是用摄像机拍摄的慢动作镜头,效果惊艳! 这个项目的核心优势在于: 1. **统一单网络架构**

gitblog_00920的博客 472

C++坑人游戏[0.8++版本]

这次,之所以说是0.8++版本,还是该感谢YR_T长期以来的大力支持,为我带来了一段“坑人+”的代码,而又在我不断地搜索下,总结出来一段“坑人++”的代码,接下来就直接为大家展示编辑好的0.8++版本。 Dev-C++版: #include <iostream> #include <fstream> #include <Windows.h> #include <conio.h> #include <string.h> #include &

一枚初中生的博客 2834

c摘要

 想想学习C已经有9年了, 应该可以写一些东西了.ID: 长久 性别: 男 最好的朋友: 电脑 特点: 近视900 脑子一根筋 E-mail: yl_changjiu@163.com 写在前边想想学习C已经有9年了, 应该可以写一些东西了.请大家不要见笑, 敬请批评指正. (yl_changjiu@163.com)C 古老而永恒的语言 by 长久 Preface 在

updownboy的专栏 567

c++编程小游戏杀手1.1.0版本

杀手1.1.0版本 第一次发文章,希望给些赞。 有的bug还没修好,望理解。 #include<bits/stdc++.h> #include<windows.h> int again,cho,num,about,fla=0; int three=0,five=0,ten=0; long long money=0;long shop[4],pric[5]={0,30,60...

Jeffrey2020的博客 614

区域生长法的编程实现——程序员数字图像处理第一步

数字图像处理的书数不胜数。相关的方法,从直方图、卷积到小波、机器学习方面的方法也举不胜举。 OpenCV库给我们提供了一整套图像存储、显示方法外,也集成了很多很多的图像、视频处理算法以及机器学习算法,以函数的形式提供给我们使用。 然而在初学阶段,我们往往过分依赖于OpenCV中的那些库函数。 虽说OpenCV集成了很多高效算法,然而,毕竟不是无所不包。 OpenCV中基础的算法有时

Bai的博客 2万+

折腾MFC无爱~看看OpenCV自带的鼠标、键盘消息处理机制。

俺最近在做个不正式的测试程序,实在不想折腾MFC。List、Control等等控件,还有种种消息响应处理,实在有点繁琐。 于是就用OpenCV自带的消息处理程序试了一下,马马虎虎能够解决问题,但还要用到命令行输入,非“傻瓜”程序。 OpenCV 键盘、鼠标响应函数都比较简单。 键盘: cvWaitKey() 你没有看错,这个居家旅行人手必备的货,原型居然是带返回值的。用它

Bai的博客 3629

对ANSIUnicode的一点理解

最近在读《Windows核心编程》,加上一个批处理程序的需求,渐渐对ANSI跟Unicode字符有些理解了。在这里写个小结。 1、运算 wchar_t strW[100] = L"这是个..."; //这是Unicode char str[100] = "这是个..."; //这是ANSI Unicode在C++中的形式多为宽字符(wchar_t)

Bai的博客 1047

qt,c++为什么要进行序列化反序列化。已经 1 字节对齐 `#pragma pack(1)`,为什么还要 QDataStream?

qt,c++为什么要进行序列化反序列化。已经 1 字节对齐 `#pragma pack(1)`,为什么还要 QDataStream?

sunflower_2020的博客 69

c语言分支与循环语句

分支决定程序“走哪条路”,循环决定程序“重复多少次”,跳转语句则负责在必要时改变当前执行节奏。掌握这些语句的语法只是起点,更重要的是理解它们的执行顺序、作用范围边界条件。当你能够熟练地把ifswitchwhilefordo...whilebreakcontinue组合起来,就可以从简单的判断题、循环题,逐步写出登录验证、查找算法交互式小游戏等完整程序。清晰的控制流,是写出可靠 C 程序的基础。

phltxy的博客 168

C++】线程库

本文系统介绍C++多线程编程:涵盖线程创建、join/detach、this_thread;深入讲解互斥锁(普通、递归、超时、自旋)及RAII管理,对比lock_guard与unique_lock;介绍atomic原子操作与CAS无锁编程;最后详解条件变量,包括生产者-消费者模型、核心API及注意事项,并给出交替打印的实现。

wefg1的博客 194

c++信息学竞赛数组大小规划与避坑速查表

做题时先看数据范围,按“最大值+5”的原则开数组;如果是大数组,一律放在全局变量区;遇到极端大数据,果断上。

pxklove1214的博客 341

C++ 如何优雅解决类的循环依赖?

C++循环依赖导致编译错误,因编译器单遍扫描需完整类型。解法是前置声明、类内只声明函数,类外延后实现。编译器允许不完整类型用作指针、引用及函数原型,待完整定义后填充实现。但仅为语法解耦,更优做法是引入共享状态中间层,消除双向强耦合与生命周期隐患。

Lion_Long的博客 616

Debug20190111_Hikvision_labview_control_

Hikvision display control

上一篇: OpenCV中调用cvReleaseMemStorage释放CvSeq内存时的一个奇怪问题
下一篇: Makefile最简版本,看完你就会写Makefile了
Sera_ph
博客等级 码龄14年 35粉丝 11原创
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值