c++构造函数总结----C++拷贝构造函数及重写operator =的区别

C++拷贝构造函数及重写operator =的区别 先来代码:#include using namespace std; class CA { public:     CA(int b)     {         cout         a=b;     }     CA(const CA& C) // 拷贝构造函数     {         cout         a=C.a;     }     CA& operator=(const CA& C)//重写operator=     {         co 阅读详情
c++构造函数的知识在各种c++教材上已有介绍,不过初学者往往不太注意观察和总结其中各种构造函数的特点和用法,故在此我根据自己的c++编程经验总结了一下c++中各种构造函数的特点,并附上例子,希望对初学者有所帮助。

c++类的构造函数详解:                        

一、 构造函数是干什么的

class  Counter
{

public :
          // 类Counter的构造函数
          // 特点:以类名作为函数名,无返回类型
         Counter()
         {
                m_value = 0;
         }
         
private :
      
          // 数据成员
          int  m_value;
}


       该类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数->由构造函数完成成员的初始化工作

eg:    Counter c1;
        编译系统为对象c1的每个数据成员(m_value)分配内存空间,并调用构造函数Counter( )自动地初始化对象c1的m_value值设置为0

故:

        构造函数的作用:初始化对象的数据成员。

二、 构造函数的种类

class  Complex 
{         

private  :
         double     m_real;
         double     m_imag;

public :

         //    无参数构造函数
         // 如果创建一个类你没有写任何构造函数,则系统会自动生成默认的无参构造函数,函数为空,什么都不做
         // 只要你写了一个下面的某一种构造函数,系统就不会再自动生成这样一个默认的构造函数,如果希望有一个这样的无参构造函数,则需要自己显示地写出来
        Complex( void )
        {
             m_real = 0.0;
             m_imag = 0.0;
        } 
        
         //    一般构造函数(也称重载构造函数)
         // 一般构造函数可以有各种参数形式,一个类可以有多个一般构造函数,前提是参数的个数或者类型不同(基于c++的重载函数原理)
         // 例如:你还可以写一个 Complex( int num)的构造函数出来
         // 创建对象时根据传入的参数不同调用不同的构造函数
        Complex( double  real,  double  imag)
        {
             m_real = real;
             m_imag = imag;         
         }
        
         //    复制构造函数(也称为拷贝构造函数)
         //    复制构造函数参数为类对象本身的引用,用于根据一个已存在的对象复制出一个新的该类的对象,一般在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中
         //    若没有显示的写复制构造函数,则系统会默认创建一个复制构造函数,但当类中有指针成员时,由系统默认创建该复制构造函数会存在风险,具体原因请查询 有关 “浅拷贝” 、“深拷贝”的文章论述
        Complex( const  Complex & c)
        {
                 // 将对象c中的数据成员值复制过来
                m_real = c.m_real;
                m_img    = c.m_img;
        }            
    
         // 类型转换构造函数,根据一个指定的类型的对象创建一个本类的对象
         // 例如:下面将根据一个double类型的对象创建了一个Complex对象
        Complex::Complex( double  r)
        {
                m_real = r;
                m_imag = 0.0;
        }


三、等号运算符重载(和拷贝构造函数关系)

         // 等号运算符重载
         // 注意,这个类似复制构造函数,将=右边的本类对象的值复制给等号左边的对象,它不属于构造函数,等号左右两边的对象必须已经被创建
         // 若没有显示的写=运算符重载,则系统也会创建一个默认的=运算符重载,只做一些基本的拷贝工作
        Complex & operator =(  const  Complex &rhs )
        {
                 // 首先检测等号右边的是否就是左边的对象本,若是本对象本身,则直接返回
                 if  (  this  == &rhs ) 
                {
                         return  * this ;
                }
                
                 // 复制等号右边的成员到左边的对象中
                 this ->m_real = rhs.m_real;
                 this ->m_imag = rhs.m_imag;
                
                // 把等号左边的对象再次传出
                // 目的是为了支持连等 eg:    a=b=c 系统首先运行 b=c
                // 然后运行 a= ( b=c的返回值,这里应该是复制c值后的b对象)    
                 return  * this ;
        }

};

【可见=运算符行为类似拷贝构造函数,但它不属于拷贝构造函数,完全是两个东西。另外,如果一个类中没有显示的重写=运算符,则系统会自动创建一个默认的等号运算符重载,只是依次复制各个成员。】


下面使用上面定义的类对象来说明各个构造函数的用法:
void  main()
{
         // 调用了无参构造函数,数据成员初值被赋为0.0
        Complex c1,c2;

         // 调用一般构造函数,数据成员初值被赋为指定值
        Complex c3(1.0,2.5);
         // 也可以使用下面的形式
        Complex c3 = Complex(1.0,2.5);
        
         //    把c3的数据成员的值赋值给c1
         //    由于c1已经事先被创建,故此处不会调用任何构造函数
         //    只会调用 = 号运算符重载函数
        c1 = c3;
        
         //    调用类型转换构造函数
         //    系统首先调用类型转换构造函数,将5.2创建为一个本类的临时对象,然后调用等号运算符重载,将该临时对象赋值给c1
        c2 = 5.2;
        
        // 调用拷贝构造函数( 有下面两种调用方式) 
        Complex c5(c2);
        Complex c4 = c2;   // 注意和 = 运算符重载区分,这里等号左边的对象不是事先已经创建,故需要调用拷贝构造函数,参数为c2
}

四、思考与测验

1. 仔细观察复制构造函数

        Complex( const  Complex & c)
        {
                 // 将对象c中的数据成员值复制过来
                m_real = c.m_real;
                m_img = c.m_img;
        }    
        
为什么函数中可以直接访问对象c的私有成员?

2. 挑战题,了解引用与传值的区别

  Complex test1( const  Complex& c)
  {
           return  c;
  }
  
  Complex test2( const  Complex c)
  {
          return  c;
   }
   
   Complex test3()
   {
           static  Complex c(1.0,5.0);
           return  c;
   }
  
  Complex& test4()
  {
          static  Complex c(1.0,5.0);
          return  c;
  }
  
   void  main()
  {
        Complex a,b;
    
         // 下面函数执行过程中各会调用几次构造函数,调用的是什么构造函数?
    
       test1(a);
       test2(a);
     
       b = test3();
       b = test4();
     
       test2(1.2);
        // 下面这条语句会出错吗?
       test1(1.2);      //test1( Complex(1.2 )) 呢?
  }
 

五、附录(浅拷贝与深拷贝)

       上面提到,如果没有自定义复制构造函数,则系统会创建默认的复制构造函数,但系统创建的默认复制构造函数只会执行“浅拷贝”,即将被拷贝对象的数据成员的 值一一赋值给新创建的对象,若该类的数据成员中有指针成员,则会使得新的对象的指针所指向的地址与被拷贝对象的指针所指向的地址相同,delete该指针 时则会导致两次重复delete而出错。下面是示例:
 
【浅拷贝与深拷贝】
#include <iostream.h>
#include < string .h>
class  Person 
{
public  :
        
         // 构造函数
        Person( char  * pN)
        {
              cout <<  "一般构造函数被调用 !\n" ;
              m_pName =  new   char [strlen(pN) + 1];
               //在堆中开辟一个内存块存放pN所指的字符串
               if (m_pName != NULL) 
              {
                  //如果m_pName不是空指针,则把形参指针pN所指的字符串复制给它
                   strcpy(m_pName ,pN);
              }
        }        
        
         // 系统创建的默认复制构造函数,只做位模式拷贝
        Person(Person & p)    
        { 
                   //使两个字符串指针指向同一地址位置         
                 m_pName = p.m_pName;         
        }
   
        ~Person( )
        {
                delete m_pName;
        }
        
private  :

         char  * m_pName;
};

void  main( )
{ 
        Person man( "lujun" );
        Person woman(man); 
        
         // 结果导致   man 和    woman 的指针都指向了同一个地址
        
         // 函数结束析构时
         // 同一个地址被delete两次
}


// 下面自己设计复制构造函数,实现“深拷贝”,即不让指针指向同一地址,而是重新申请一块内存给新的对象的指针数据成员
Person(Person & chs);
{
          // 用运算符new为新对象的指针数据成员分配空间
         m_pName= new   char [strlen(p.m_pName)+ 1];

          if (m_pName)         
         {
                  // 复制内容
                strcpy(m_pName ,chs.m_pName);
         }
      
         // 则新创建的对象的m_pName与原对象chs的m_pName不再指向同一地址了

}

参考自:http://blog.163.com/haixing_03031102/blog/static/120105509200972855328532/

类的三个特殊成员Copy Constructor、Copy-Assignment Operator、Destructor重载与使用 今天看《C++ Primer》的13.1节——Copy, Assign, and Destroy 被这几个玩意儿弄得晕得不行:   ◆   Copy Constructor   ◆   The Copy-Assignment Operator   ◆   Destructor 主要问题集中在:   ◆   我们在什么时候需要自己重写? 阅读详情

相关推荐

【RDMA】13. RDMA之用户态与内核态交互

原文:https://zhuanlan.zhihu.com/p/346708569 在“RDMA之Verbs”一文中我们说道,Verbs API分为用户态和内核态,分别以ibv_和ib_作为前缀。RDMA技术的最大的优势就在于用户态可以绕过内核,直接控制硬件收发数据,减少了系统调用和内存拷贝次数,所以大部分的RDMA应用都是用户态应用,即使用以ibv_为前缀的用户态Verbs API。 但是并非所有的用户态Verbs API都可以完全绕开内核,本文中我来讲解一下哪些API依赖于内核RDMA子系统(包括驱

我的笔记本 4285

C++之operator()和构造函数区别与总结(二百三十)

本篇目的:理解C++之operator()和构造函数区别与总结。

Android系统攻城狮 981

波克 上海 Unity开发笔试题 2024

主要分为四部分,如果没有准备好,不要点击笔试链接,进入就会自动开始。

z2014z的博客 3392

c++ 中 operator总结

1、operator作类的转换函数 类可以使用构造函数将其他类型转化为此类的对象,比如 my_class a = my_class(int i); 将int型转化为my_class类的一个对象。 同样,也可以使用类的转换函数将类的对象转化为其他的类型。 类的转换函数应当满足以下的几个条件: 转换函数必须是类方法 转换函数不能指定返回类型 转换函数不能有参数 下面是一个类转化函数的例子 #include <iostream> using namespace std; class my_c

changyi9995的博客 2719

银河麒麟(桌面版/服务器版)远程桌面配置全攻略:XRDP与VNC实战指南

本文提供了银河麒麟操作系统(桌面版与服务器版)配置远程桌面的完整实战指南。详细对比并演示了XRDP与VNC两种主流方案的安装、配置与连接步骤,涵盖从环境准备、软件安装、服务启动到客户端连接的全过程,并针对常见的黑屏、连接失败等问题给出了有效的排坑解决方案,帮助用户实现跨平台的便捷图形化远程管理。

b0c1d2的博客 808

Linux下开机异常(fsck exited with status code 4)

Linux下开机异常事情是这样的,本来我呢跑着程序听着歌,结果忽然就死机了,我只能强制关机,再次打开系统的时候,就提示这样fsck from util-linux 2.26.2 /dev/sda10 contains a file system with errors, check forced. /dev/sda10: Inodes that were part of a corrupted pr

芳草碧连天 2万+

C++:函数指针进阶(四):函数对象operator()

C++:函数指针进阶(四):函数对象operator()

C++ JAVA的专栏 3664

ZLMediaKit源码分析(二)推流创建

ZLMediaKit推流结构体创建是在RtspSession::onRecv()之后。如何触发onRecv()请参考上一篇文章这里不在赘述。

cliffordl的专栏 5068

C++拷贝构造函数和operator=

1 拷贝构造函数参数的特点对于一个类X,如果一个构造函数的第一个参数是下列之一:a) X&b) const X&c) volatile X&d) const volatile X&因此 X::X(X&, int=1); //是拷贝构造函数 并且类中可以存在超过一个拷贝构造函数。拷贝构造函数采用引用作参数原因:1) 效率 。2) 避免死循环。 当一个对象需要以值方式传递时,编译器会生成代码调用它的拷

starryheavens的专栏 1万+

别再死磕公式了!用Python+NumPy手把手实现机器人逆运动学数值求解(附避坑指南)

本文详细介绍了如何使用Python和NumPy实现机器人逆运动学(Inverse Kinematics, IK)的数值求解方法,包括牛顿-拉弗森法、雅可比矩阵计算及奇异位形处理。通过实战代码和避坑指南,帮助开发者快速掌握现代机器人学中的核心算法,提升工程实践能力。

weixin_30687051的博客 126

从一个 ASIN 看透亚马逊:商品模型背后的增长飞轮

在亚马逊电商体系中,每件商品背后都有一套严密的商品建模逻辑。本篇文章以“ASIN 的一生”为线索,系统拆解了亚马逊的商品模型:从飞轮战略出发,剖析 SDP(Single Detail Page)机制如何实现标准化展示;再到 ASIN 编码、父子变体结构与 Offer 分离模型,逐层解析商品信息如何被建构、聚合与呈现。通过图解与案例,文章帮助读者理解商品建品流程、同款聚合原则、价格控制机制等核心逻辑,避免常见运营误区,是一份面向运营、产品、技术人员的实用参考指南。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 13万+

浅显易懂的《C++类和对象》-中篇

内容充实、概念易懂,C++类和对象中篇,类的6个默认成员函数,轻松掌握。

. 3300

在 ABAP CDS View 里把 Conversion Functions 用到极致:FLTP 精度、单位换算、货币换算与小数位处理的工程化实践

数据格式转换在真实项目中比业务逻辑更容易引发问题。ABAP CDS中的转换函数(如FLTP_TO_DEC、UNIT_CONVERSION、CURRENCY_CONVERSION和DECIMAL_SHIFT)可帮助在数据库层统一数据口径,避免应用层重复处理。这些函数支持数值精度治理、单位换算、货币转换和小数位调整,能显著提升报表性能并减少逻辑分散。通过将格式转换前移到数据模型层,可以确保服务层和UI层的数据一致性,同时降低接口传输错误风险。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 2349

C++拷贝构造函数深入分析以及重写operator =

  class CTestCopyConstruct { public : CTestCopyConstruct() { TRACE( " Enter CTestCopyConstruct();this is %d/n " , this ); strTest = " not ok " ; i = 0 ;

Codelife 1779

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

深入分析C++赋值运算符重载函数(operator=)

http://www.cnblogs.com/zpcdbky/p/5027481.html 关于C++的赋值运算符重载函数(operator=),网络以及各种教材上都有很多介绍,但可惜的是,内容大多雷同且不全面。面对这一局面,在下在整合各种资源及融入个人理解的基础上,整理出一篇较为全面/详尽的文章,以飨读者。 正文: Ⅰ.举例 例1 #include #i

jeffasd的专栏 571

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

c++的构造函数赋值函数重载运算符等

c++的类的特殊函数实在让人又爱又恨,构造函数,拷贝函数,移动构造,赋值函数,重载运算符等等… 在给与我们很大操作空间的同时,学习曲线着实有些陡峭了。在此记录一下日常笔记,后续会不断补充类相关的函数,努力吧青年!参考: c++的拷贝构造函数被调用的时机 C++的四个默认函数(构造函数,析构函数,拷贝函数,赋值函数) 当类对象被用来初始化另一个对象的时候会触发。参考:c++类中的赋值函数 主要是为了重写函数,在函数中判断对象是否相等,不相等则把类中的成员变量都重新赋值一遍,然后返回类对

铁柱的博客 1264

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

C++编程思想笔记之五

第10章   引用和拷贝构造函数一、使用引用时有一定的规则:1) 当引用被创建时,它必须被初始化。(指针则可以在任何时候被初始化。)2) 一旦一个引用被初始化为指向一个对象,它就不能被改变为对另一个对象的引用。(指针则可以在任何时候指向另一个对象。)3) 不可能有N U L L 引用。必须确保引用是和一块合法的存储单元关连。 二、参数传递准则当给函数传递参数时,人们习惯上应该是通过常量

jinfeng_wang的专栏 1548

C/C++基础知识点面试题

目录 一、虚函数的数据结构,如何工作? 二、const与define的区别? 三、指针与引用的区别? 四、指针与数据的区别? 五、不用临时变量实现两个变量的交换 七、一个C++源文件从文本到可执行文件经历的过程 八、C++11新特性 九、C++和C的不同 十、malloc的原理 十一、内存泄漏、野指针 十二、static 十三、union和struct 十四、new与ma...

找个特立不独行的名的博客 2万+

深入理解C++构造函数:从初始化列表到RAII资源管理

构造函数是C++面向对象编程的核心概念,它定义了对象创建时的初始化行为。其原理在于确保对象在诞生之初就处于有效状态,这是实现资源管理(RAII)和编写异常安全代码的基础。在工程实践中,合理使用构造函数能显著提升代码的健壮性和性能,尤其在管理动态内存、文件句柄等资源时至关重要。初始化列表作为构造函数的高效初始化机制,不仅是处理常量成员、引用成员的唯一途径,还能避免不必要的默认构造与赋值开销。本文通过一个动态数组类的实战案例,深入解析了默认构造、拷贝构造、移动构造等不同构造函数的使用场景与设计要点,帮助开发者掌

weixin_30527423的博客 369

C++:12---运算符重载(operator)

一、概念 对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型 重载的运算符是具有特殊名字的函数,该函数也有返回值、参数列表、函数体 二、运算符重载的3种实现方式 成员函数:私有、公有、保护都可以 友元函数:同上 全局函数:只能访问公有的 三、运算符重载的规则 以下运算符不支持重载:.(类属运算符),::(作用域运算符),sizeof,?:(三目运算符),#(预处理...

董哥的黑板报 1336

effective c++条款10-12(operator=(重载返回类型、自我赋值和深层复制))整理

一、重载operator=返回类型 下面举例说明,operator=类似。 针对:ostream & operator 说明几点: 1.第一个形参为对ostream对象的引用,在该对象上将产生输出,ostream为非const,因为写入到流会改变流的状态;该形参是一个引用,因为不能复制ostream对象(在c++中定义的标准输入输出流类istream和ostream,其中拷贝构造函数和赋

hustyangju的足迹 1418

C++默认成员函数全解析:从构造到析构,掌握对象生命周期管理

在C++面向对象编程中,类的特殊成员函数是对象生命周期管理的核心机制。这些函数包括构造函数、析构函数、拷贝操作和移动操作,它们共同决定了对象的创建、复制、移动和销毁行为。理解这些函数的原理对于编写高效、安全的C++代码至关重要,特别是在涉及动态内存管理时。编译器会自动生成这些函数的默认版本,但默认实现往往只进行浅层操作,当类管理动态资源(如堆内存)时,浅拷贝会导致严重的资源管理问题,如内存泄漏和双重释放。因此,掌握如何正确实现这些函数,特别是深拷贝和移动语义,是提升代码健壮性和性能的关键。本文通过实际案例深

weixin_33853827的博客 431

重载运算符中的const_C++ Lesson 11:运算符重载operator overloading

在最近的事例中,我发现,对于构造器出现了很多知识点。因此这一部分还不能够跳过去。一、运算符重载[1]函数重载:多次调用同名函数、传参不同。从而不必为不同名字的变量重写函数。我们能够对于不同类型的数据,采取运算符重载。1、运算符int 2、运算符重载的限制不能够被重载的运算符:条件(?),sizeof,scope(::),成员选择(.),成员指针选择(.*),casting operator。只能够...

weixin_39611072的博客 242
上一篇: C++模版中的typename关键字和嵌套依赖类型(依赖名称)
下一篇: c++推荐看的一些经典书籍
HNFXS985
博客等级 码龄14年 219粉丝 150原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值