C++中复制构造函数与重载赋值操作符的深入分析

发布者:pengbinyyy最新更新时间:2015-05-05 来源: 51hei关键字:C++  构造函数  重载赋值  操作符 手机看文章 扫描二维码
随时随地手机看文章
   在C++中复制控制是一个比较重要的话题,主要包括复制构造函数、重载赋值操作符、析构函数这三部分,这三个函数是一致的,如果需要手动定义了其中了一个,那么另外的两个也需要定义,通常在存在指针或者前期相关操作的情况下,都需要手动的定义。复制构造函数与重载赋值操作符实现的大题相同,如果没有手动的实现,那么编译器会自动生成一个,而且这两个函数的参数也是一致的,是不能够改变的,这是为什么呢?这是值得我们去分析和推敲的。析构函数相比前面的两个存在一个巨大的差别,就是无论我们是否定义这个函数,编译器都会自动生成一个析构函数。析构函数我认为主要是完成对象的释放操作,我就不去仔细的分析啦。

   
    我们现在着重来分析一下为什么复制构造函数与重载赋值操作符在没有定义的情况下,编译器会为我们生成一个,这说明这两个函数是一个类必不可少的部分。由此可知如果一个类没有定义任何的东西,编译器也会帮助我们生成下面的4个函数:1、一个构造函数,也就是所谓的类名比如classname(),这是在没有定义构造函数时,编译器会自动生成的。2、析构函数,这个前面已经提到了。3、复制构造函数。4、重载赋值操作符。
 
    为什么复制构造函数和重载赋值操作符如此重要呢?
   
    首先介绍一下复制构造函数与重载赋值操作符的声明形式,这两个函数的参数是固定的,是不能改变的。假设存在一个类Base。那么它的这两个函数声明分别如下所示:

 

    class Base
    {
    public:
        //构造函数
        Base();
        //复制构造函数
        Base(const Base &);
        //重载赋值操作符
        Base &operator=(const Base &);
        //析构函数
        ~Base();
        ...
    private:
        ...
    };

    面的形式可以知道,复制构造函数与重载赋值操作符的参数是一致的,都是该类的const引用类型。为什么不能重载呢?这些都是存在的问题。我觉得要搞清楚这些问题,首先我们就不能只能片面的去理解,而是应该对C++的面向对象编程有了一个较好的理解以后再来分析这个问题。
 
    么是引用,很多书上都会说是为了避免复制,这是其中的一个原因,如果说只是这个原因,完全可以只用指针就可以了,对于系统而言,不在乎多几个指针的存储空间。
首先说明一下在C++中的继承问题,一般而言我们的继承主要是指公共继承,也就说如下的派生类定义所示:

 

    class Derived : public Base
    {
     public:
       ...
    private:
       ...
    }

    公共继承而言,基类的公共部分成为了派生类的公共部分,私有部分成为了派生类的私有部分。也就是说派生类中包含基类的部分。也就是说在实现派生类的过程中,基类的公用接口会被派生类直接继承。而基类的私有成员也作为派生类的私有成员。但是对于其他的继承类型,我就不去讨论啦。这时派生类的成员可以访问到基类的私有成员。也就是说相当于派生类是在基类的基础上增加了自己的特色。
 
    需要介绍一个问题就是采用派生类对象的引用初始化基类的引用。多态性的动态绑定中存在两个条件:1、必须是virtual函数(虚函数),2、必须是通过基类的引用或者基类的指针进行成员虚函数的调用。
只有上面两个条件满足才能发生动态调用问题。
 
    由于派生类中存在基类的成员,也就相当于一个派生类对象中包含了一个基类对象(我不知道这样是否合理),所以可以采用一个基类引用来绑定一个派生类对象。引用实质上是针对一块内存区域,引用是一个标号,是这块内存区域的一个名字,一个引用与一块内存区域绑定,因为派生对象中存在基类部分,可以认为派生对象的区域中存在基类对象,这时可用基类的引用来表明这块内存区域,即采用一个基类的别名来表示(绑定)这段内存区域,派生对象的地址(这段内存)以及内容都没有发生改变,也没有重现创造出一个新的对象,基类的引用还是指向这个派生对象。对于指针的分析方式相似。因此可以采用基类的引用绑定派生类对象。
   
    但是如何实现派生类对象到基类的转换呢?
    这时候的转换与前面的绑定存在很大的差别,因为这是重新分配一个基类对象,而不再是引用问题,不再是绑定问题,是依据一个派生类对象生成一个新的基类对象。因为派生类对象中存在一个基类对象基本的信息,完全可以生成一个基类对象,完全将此过程看作是一个初始化或者赋值的问题。也就是采用派生类创建一个新的对象或者赋值一个对象。
    从上面的分析我们可以采用下面的形式来实现:

 

    Base(const Derived &);
    Base &operator=(const Derived &);

    是在基类函数中采用构造函数基于派生类来重载一系列的构造函数,但是这也存在一个问题,如果存在很多派生类,这时候就要重载很多构造函数,这肯定不是我们需要的。
 
    这时候是否发现与前面的问题关联起来了?
    这时候我们发现对于一个类而言,为什么复制构造函数和重载赋值操作符这么重要了。因为这两个函数都是接受一个基类的引用,根据前面的分析我们知道一个基类引用完全可以绑定一个派生类的对象,而派生类对象中又包含了一个基类对象的基本信息。我们能够实现一个从一个派生对象到基类的构造过程。
    我们用一个基类引用绑定一个派生对象,然后采用基类引用对基类成员进行访问,完成了一个基类对象基本要素的填充操作,相当于完成了基类对象的创建,也就是构造问题。这样也就能完成由派生类对象到基类对象的构造过程。
    至于为什么是一个const的引用,我认为主要是因为不去修改派生类对象和扩大能够接受的参数情况,由const引用可以绑定不同类型的对象特性,说明const引用会扩大接受实参的能力。
 
现在我可以总结起来说了,因为在复制构造函数中,C++中的基类引用可以绑定一个派生类的对象,如果在允许访问的情况下,采用基类引用可以访问基类的成员以及派生类的其他成员,采用引用可以复制派生类对象中基类成员的值到新创建的基类成员中,完成一个基类成员数据的填充操作,这时候一个完整的基类对象就创建完成了。
 
    重载赋值操作符则是发生在使用一个派生对象来赋值一个基类对象时,这时候也是const基类引用绑定一个派生类对象,然后复制对应的基类成员到基类对象对于的成员中,完成一个基类对象成员的更新操作。
 
    来说,复制构造函数不仅仅实现了同类型之间的初始化操作,同时也完成了采用一个派生类对象初始化一个基类对象的操作,重载赋值操作符实现了同类型之间的赋值操作,也完成了采用派生类对象赋值基类对象的操作。如果没有这两个函数的存在,也就不能完成派生类到基类的赋值和初始化操作。这也是为什么一定会存在这两个函数的原因。

关键字:C++  构造函数  重载赋值  操作符 引用地址:C++中复制构造函数与重载赋值操作符的深入分析

上一篇:C/C++中关于局部函数中更新实参指针的方法
下一篇:C++中类的内存空间大小(sizeof)分析

推荐阅读最新更新时间:2024-03-16 14:00

c语言多文件 6410 led裸机程序
// led4 gpk7 // led3 gpk6 // led2 gpk5 // led1 gpk4 0 ,light //u32 rGPIOKCON0; //0x7f008800 // u32 rGPIOKCON1; //0x7f008804 // u32 rGPIOKDAT; //0x7f008808 //u32 rGPIOKPUD; //0x7f00880c #include def.h #include gpio.h #define led1on ~(1 4) #define led2on ~(1 5) #define led3on ~(1 6) #define led4on ~(1
[单片机]
七彩灯综合C程序
/*此程序是一款普通的彩灯,它的功能主要有四种模式: 第一种模式:开机四种颜色以0.5秒速度循环1次,然后 在白颜色上停止循环,即显示白光 第二种模式:按下功 能键后,它以1秒速度四种颜色不停的循环 第三种模式: 当按键按下后,它会记住第二种模式的颜色,比如第二种 模式现在亮得是绿色,你按下按键时,它会先闪一下,然 后在绿颜色上停下来 第四模式:当你再按下开关时,它 自动回到模式一下,(当然还可以写出三种颜色) 本程序是第一个版本,第二版功能更强大参见: http://www.51hei.com/mcu/1531.html */ #include reg52.h #define uint unsigned int #defi
[单片机]
s3c6410的RTC在linux中的驱动(5)
在上一篇中我们在中分析了RTC驱动的注册和注销,重点讲了平台设备驱动的probe函数,最后引出了这篇我们要讲解的内容,那就是下面这个结构体中的一些函数。 static const struct rtc_class_ops s3c_rtcops = { .open= s3c_rtc_open, .release = s3c_rtc_release, .ioctl = s3c_rtc_ioctl, .read_time = s3c_rtc_gettime, .set_time = s3c_rtc_settime, .read_alarm = s3c_rtc_getalarm, .set_alarm = s3c_rtc_seta
[单片机]
s3<font color='red'>c</font>6410的RTC在linux中的驱动(5)
The MathWorks宣布从MATLAB中自动生成可嵌入C 代码功能
        嵌入式 MATLAB 子集转换成有效嵌入式代码 美国马萨诸塞州内蒂克市(NATICK, Mass.) – 2007年10月1日 – The MathWorks 今日推出了嵌入式 MATLAB ――业界领先的 MATLAB 科学计算语言的子集。 嵌入式 MATLAB 子集使 MATLAB 用户能够从 MATLAB 程序中生成高效、可嵌入 C 代码,从而避免了常见的、耗时的和易出错的用 C 代码重写 MATLAB 算法的进程。 嵌入式 MATLAB 子集包括了众多的 MATLAB 功能,有 270 多个 MATLAB 运算符和函数以及90 多个定点工具箱(Fixed-Point Toolbox)函数。嵌入式 MA
[新品]
提高PIC16C711单片机片内A/D分辨率的方法
摘要:介绍一种将PIC16C711片内8位A/D提高到11位的方法。此方法电路简单,速度快,可提高单片机应用系统的性能价格比,具有一定的推广价值。 关键词:PIC16C711 单片机 A/D 分辨率 目前,单片机中嵌入的A/D一般为8位到10位,难以满足信号处理应用中高分辨率的要求;而外接高分辨率的A/D将使成本明显提高,因为A/D转换器的价格将随其位数的增加而成倍增加。本文介绍一种提高PIC16C711单片机片内A/D分辨率的方法,将PIC16C711片内的8位A/D提高到11位。这种方法在PIC系列的其他单片机也适用。 美国Microchip公司推出的8位单片机PIC16C711是一种性能价格比很高的单片机。它价格低、封
[单片机]
三款LG超轻薄笔记本电脑采用高集成度的赛普拉斯 USB-C 解决方案
加利福尼亚州圣何塞,2017年3月27日 — USB-C市场领导者赛普拉斯半导体公司 (纳斯达克代码:CY)今日宣布 LG 电子 (LG Electronics)采用其业内集成度最高的 USB-C 解决方案 - 赛普拉斯 EZ-PD™CCG3 控制器,推出三款全新的超轻薄 LG gram 笔记本电脑。CCG3 控制器集成了多种器件并支持全新的 USB-C UCSI 连接标准,满足 LG产品对尺寸和功能的需求。LG Gram 13 寸、14 寸 及 15 寸笔记本电脑均配置 CCG3 控制器。更多关于赛普拉斯EZ-PD CCG3 控制器的信息,敬请访问:http://www.cypress.com/ccg3。 LG 在赛普拉斯设
[家用电子]
用P89C664实现I2C总线大批量数据的自动存储
引言 在实际工作中,有些情况下可能需要对一些I2C接口发出的数据进行分析,如果数据较少则比较容易解决。比如可以直接把数据保存到单片机的RAM中,然后通过LED显示出来,但如果数据量很大,这种方法就很河取了。在这种情况下,想办法把大量的数据保存到电脑里是一个比较好的方法这样不但可以解决大批量数据的存储问题,同时也易于编辑、分析和打印。 但是,电脑的外设接口中是没有I2C接口的,因此需要对I2C部迟疑不决的数据进行转换,使之能发往电脑,实现数据的文件存储。综合各种因素考虑,采用UART串口的方式比较方便,因为串口技术简单、应用广泛、各种应用软件也较为丰富。 本文不仅介绍了如何实现I2C数据的转发和自动存储,同时也介绍了P8
[嵌入式]
stc12c5a60s2复位电路说明
STC12C5A60S2在众多的51系列单片机中,要算国内STC 公司的1T增强系列更具有竞争力,因他不但和8051指令、管脚完全兼容,而且其片内的具有大容量程序存储器且是FLASH工艺的,如STC12C5A60S2单片机内部就自带高达60K FLASHROM,这种工艺的存储器用户可以用电的方式瞬间擦除、改写。而且STC系列单片机支持串口程序烧写。显而易见,这种单片机对开发设备的要求很低,开发时间也大大缩短。写入单片机内的程序还可以进行加密,这又很好地保护了你的劳动成果。 stc12c5a60s2内部结构图 stc12c5a60s2内部结构图如下: stc12c5a60s2复位电路 就是在复位引脚接1个10UF电容到电源+,
[单片机]
stc12<font color='red'>c</font>5a60s2复位电路说明
热门资源推荐
热门放大器推荐
  •  zip文件Beetle ESP32 C6迷你开发板原理图和尺寸图
  •  pdf文件FireBeetle 2 ESP32 C6开发板尺寸图
  •  pdf文件FireBeetle 2 ESP32 C6开发板原理图
  •  pdf文件ESP32-C6 系列芯片手册
  • 系统发生错误

    系统发生错误

    您可以选择 [ 重试 ] [ 返回 ] 或者 [ 回到首页 ]

    [ 错误信息 ]

    页面错误!请稍后再试~

小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved