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

C++ 特殊成员函数:默认构造函数、默认析构函数、复制构造函数、赋值运算符

  • 1、绪言
  • 2、默认构造函数
    • 2.1默认构造函数形式一
    • 2.2默认构造函数形式二
  • 3、 默认析构函数
  • 4、复制构造函数
    • 4.1、何时调用复制构造函数
    • 4.2、复制构造函数有什么功能
  • 5、赋值运算符

1、绪言

  特殊成员函数:程序员没有进行定义,但C++会自动提供的成员函数
特殊成员函数如下:
  ·默认构造函数
  ·默认析构函数
  ·复制构造函数
  ·赋值运算符
  ·地址运算符
  ·移动构造函数
  ·移动赋值运算符

  如果程序使用对象的方式需要,编译器会自动生成复制构造函数、赋值运算符、地址运算符三个函数的定义。例如,需要将一个对象赋给另一个对象,编译器将提供赋值运算符的定义。
移动构造函数和移动赋值运算符是C++11中提供的两个特殊成员函数。这两个函数会有单独的文章讲解,此处不做解读。

2、默认构造函数

  如果没有提供任何构造函数,C++将创建默认构造函数。默认构造函数不接受任何一个参数,也不执行任何操作。 以Klunk类为例,Klunk类的默认构造函数如下:

Klunk::Klunk(){ }//implicit default constructor

**如果定义了构造函数,C++将不会定义默认构造函数。如果希望在创建对象时不显式的对它进行初始化,则必须显式地定义默认构造函数。

2.1默认构造函数形式一

  默认构造函数存在两种形式,一种与编译器自动生成的类似,没有任何参数,可以使用它来设置特定的值。

Klunk::Klunk()//explicit default constructor
{klunk_ct = 0;
...}

2.2默认构造函数形式二

  还有一种格式是 带参数的构造函数,只要所有参数都有默认值。 Klunk类可以包含如下内联构造函数:

Klunk(int n = 0) {klunk_ct = n;}

需要注意的是 默认构造函数只能有一个,也就是说上述两种形式的默认构造函数只能在程序中出现一个。 如果Klunk中存在如下定义,则会产生二义性。

Klunk::Klunk(){klunk_ct = 0;}//constructor#1
Klunk(int n = 0) {klunk_ct = n;}//ambiguous constarutor#2

  当使用 Klunk bus; 语句来创建对象时,既与构造函数#1匹配,也与构造函数#2(使用默认参数0)匹配。这将导致编译器发出一条错误消息。

3、 默认析构函数

  在未定义任何析构函数时,编译器会自动生成默认析构函数,自动创建的默认析构函数与默认构造函数相似,不接受任何参数,也不执行任何操作。以Klunk类为例,默认析构函数如下:

Klunk::~Klunk(){}

4、复制构造函数

  复制构造函数用于将一个对象复制到新创建的对象中。用于初始化过程中(包括按值传递参数),而不是常规的赋值过程中。 类的复制构造函数原型通常如下:

Class_name(const Class_name &);

它接受一个指向类对象的常量引用作参数。例如,Klunk类的复制构造函数原型如下:

Klunk(const Klunk &);

对于复制构造函数必须要知道的两点:何时调用和有何功能。

4.1、何时调用复制构造函数

1.最常见的情况是将新对象显式地初始化为现有的对象。假设klunk是一个Klunk对象,以下4种声明都将调用复制构造函数:

Klunk ditto(metto);
Klunk metoo = metto; 
Klunk also = Klunk(metto);
Klunk *pKlunk = new Klunk(metto);

  其中中间两种可能会使用复制构造函数直接创建metoo何also,也可能使用复制构造函数生成一个临时对象,然后将临时对象的内容赋给metoo和also,这取决于具体的实现。最后一种声明使用metto初始化一个匿名对象,并将新对象的地址赋给pKlunk指针。

2.每当程序生成了对象副本时,编译器都将使用复制构造函数。具体地说,当函数按值传递对象函数返回对象时,都将使用复制构造函数。记住,按值传递意味着创建原始变量的一个副本。

void function(Class_name);//函数定义声明,参数为值传递方式
function(object_name);

3.编译器在生成临时对象时,也将使用复制构造函数。例如两个对象相加时,编译器会生成一个临时的类对象来保存中间结果。

  由于按值传递对象将调用复制构造函数,因此应该按引用传递对象。这样可以节省调用构造函数的时间以及存储新对象的空间

4.2、复制构造函数有什么功能

  默认的复制构造函数逐个复制非静态成员(成员复制也称为浅复制),复制的是成员的值。如果成员本身就是类对象,则将使用这个类的复制构造函数来复制成员函数。静态成员不受影响,因为它们属于整个类,而不是各个对象。

5、赋值运算符

  赋值运算符接受并返回一个指向类对象的引用。其函数原型如下:

Class_name & Class_name::operator=(const Class_name &);

将已有的对象赋给另一个对象时,将使用重载的赋值运算符

Class_name objectaB(m,n,"string");
...//对两个
Class_name  objectaA;
objectaA = objectB;//此处将调用赋值运算符

  赋值运算符与复制构造函数相似,赋值运算符的隐式实现也是对成员进行逐个复制。如果成员本身就是类对象,则程序将使用为这个类定义的赋值运算符来复制成员,但静态数据成员不受影响。
如果类中存在new动态开辟内存的情况,编译器自动提供的赋值运算符就不够用了,自动生成的赋值运算符和复制构造函数只是对指针对象进行浅拷贝,调用对象的指针成员指向被调用对象的指针成员指向的内存,当对两个对象进行清理工作时,会出现错误,对同一片内存空间进行重复清理。所以当类中存在动态内存分配时,需要自定义复制构造函数和赋值运算符,进行深拷贝,这样就可以解决对已清除的空间再进行清理的问题。

相关文章:

  • 华为C++笔试--拓扑排序
  • html css实现钟表简单移动
  • 山海鲸可视化:工厂运营的智慧之眼
  • Bug: git stash恢复误drop的提交
  • 25考研北大软微该怎么做?
  • mysql 正则表达式用法(一)
  • 【基础算法练习】Trie 树
  • 【算法专题】贪心算法
  • git的分支操作
  • 特斯拉FSD的神经网络(Tesla 2022 AI Day)
  • 自然语言处理 TF-IDF
  • 有关UE5在VisualStudio升级后产生C++无法编译的问题及处理方案
  • 【Vue】为什么Vue3使用Proxy代替defineProperty?
  • Log4j2的PatternLayout详解
  • 如何使用Python+Flask搭建本地Web站点并结合内网穿透公网访问?
  • [译]CSS 居中(Center)方法大合集
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • C++类的相互关联
  • Git初体验
  • Javascript弹出层-初探
  • jQuery(一)
  • Netty源码解析1-Buffer
  • PAT A1017 优先队列
  • SegmentFault 2015 Top Rank
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 思考 CSS 架构
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • 赢得Docker挑战最佳实践
  • 做一名精致的JavaScripter 01:JavaScript简介
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • 阿里云服务器购买完整流程
  • ​Java并发新构件之Exchanger
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • ​一些不规范的GTID使用场景
  • #《AI中文版》V3 第 1 章 概述
  • $(function(){})与(function($){....})(jQuery)的区别
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (9)目标检测_SSD的原理
  • (C)一些题4
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (笔试题)合法字符串
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)springboot“微印象”在线打印预约系统 毕业设计 061642
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (转)fock函数详解
  • (转)ORM
  • (转)VC++中ondraw在什么时候调用的
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • .Net 垃圾回收机制原理(二)
  • .NET 同步与异步 之 原子操作和自旋锁(Interlocked、SpinLock)(九)
  • .NET中使用Redis (二)
  • @WebServiceClient注解,wsdlLocation 可配置
  • [ vulhub漏洞复现篇 ] struts2远程代码执行漏洞 S2-005 (CVE-2010-1870)
  • [20140403]查询是否产生日志