c++中拷贝构造函数被调用的时机

2023-11-14

1 c++中拷贝构造函数被调用的时机

拷贝构造函数被调用的几种情况:

(1)当用类的一个对象去初始化该类的另一个对象时,系统会自动调用拷贝构造函数

(2)将一个对象作为实参传递给一个非引用类型的形参,系统会自动调用拷贝构造函数;

(3)从一个返回类为非引用的函数返回一个对象时,系统会自动调用拷贝构造函数;

(4)用花括号列表初始化一个数组的元素时,系统会自动调用拷贝构造函数。

下面逐个举例:

1.1 当用类的一个对象去初始化该类的另一个对象时,系统会自动调用拷贝构造函数

#include<ctime>
#include<cstdlib>
#include<iterator>
#include<algorithm>
#include<iostream>
#include<numeric>
using namespace std;

class MyClass {
public:
	MyClass():data(0){}
	MyClass(const MyClass& a){
		data = a.data;
		cout << "拷贝构造函数调用\n";
	}
	MyClass& operator=(const MyClass&a){
		data = a.data;
		cout << "调用赋值函数\n";
		return *this;
	}

	int data;
};



int main() {
	MyClass a;
	MyClass b(a);          // 用类的一个对象a去初始化另一个对象b
	MyClass c = a;         // 用类的一个对象a去初始化另一个对象c,注意这里是初始化,不是赋值
	return 0;
}

测试

1.2 将一个对象作为实参传递给一个非引用类型的形参,系统会自动调用拷贝构造函数

#include<ctime>
#include<cstdlib>
#include<iterator>
#include<algorithm>
#include<iostream>
#include<numeric>
using namespace std;

class MyClass {
public:
	MyClass():data(0){}
	MyClass(const MyClass& a){
		data = a.data;
		cout << "拷贝构造函数调用\n";
	}
	MyClass& operator=(const MyClass&a){
		data = a.data;
		cout << "调用赋值函数\n";
		return *this;
	}

	int data;
};

void fun1(MyClass a) {
	return ;
}


int main() {
    MyClass a;
	fun1(a);         // 形参为类对象,实参初始化形参,调用拷贝构造函数
	return 0;
}

测试

1.3 从一个返回类为非引用的函数返回一个对象时,系统会自动调用拷贝构造函数

第3点我看网上都这么说,但是实际调试的时候,发现不会调用拷贝构造函数,于是查了一下。这里默认情况下一般会被编译器优化,减少不必要的拷贝构造,所以,具体的返回值可能会因编译器及编译选项的不同而不同。使用g++编译器,关闭优化g++ xxx.cpp -fno-elide-constructors后执行结果如下(-fno-elide-constructors选项就是用来关闭拷贝优化的)

g++ xxx.cpp -fno-elide-constructors
#include<ctime>
#include<cstdlib>
#include<iterator>
#include<algorithm>
#include<iostream>
#include<numeric>
using namespace std;

class MyClass {
public:
        MyClass():data(0){}
        MyClass(const MyClass& a){
                data = a.data;
                cout << "拷贝构造函数调用\n";
        }
        MyClass& operator=(const MyClass&a){
                data = a.data;
                cout << "调用赋值函数\n";
                return *this;
        }

        int data;
};

MyClass fun2() {
        MyClass a;
        return a;
}


int main() {
        MyClass a;
        MyClass d = fun2();    // 函数返回一个类对象时, 这里可能会被编译器优化,从而可能没有调用拷贝构造

        return 0;
}

不优化编译

这里拷贝构造调用两次,一次是返回非引用的对象时调用的,一次时用返回值初始对象d时调用的。

默认优化编译

什么都不调用。

编译器具体是怎么优化的,一般编译器会先看支不支持拷贝优化,如果不支持,再看有没有定义移动构造函数,如果都没有,就调用拷贝构造函数。更具体的细节可以参考移动语义及拷贝优化的内容。

1.4 用花括号列表初始化一个数组的元素时,系统会自动调用拷贝构造函数

#include<ctime>
#include<cstdlib>
#include<iterator>
#include<algorithm>
#include<iostream>
#include<numeric>
using namespace std;

class MyClass {
public:
        MyClass():data(0){}
        MyClass(const MyClass& a){
                data = a.data;
                cout << "拷贝构造函数调用\n";
        }
        MyClass& operator=(const MyClass&a){
                data = a.data;
                cout << "调用赋值函数\n";
                return *this;
        }

        int data;
};


int main() {
        MyClass a;
        MyClass b;

        MyClass arr[2] = {a, b};

        return 0;
}

编译

2 c++中有哪几种构造函数

  • 默认构造函数
  • 初始化构造函数(有参数)
  • 拷贝构造函数
  • 移动构造函数(move和右值引用)
  • 委托构造函数
  • 转换构造函数
#include <iostream>
using namespace std;
class Student{
public:
    // 默认构造函数,没有参数
    Student(){
        this->age = 20;
        this->num = 1000;
    }
    // 初始化构造函数,有参数和参数列表
    Student(int a, int n):age(a), num(n){};
    // 拷贝构造函数,这里与编译器生成的一致
    Student(const Student& s){
        this->age = s.age;
        this->num = s.num;
    }
    // 转换构造函数,形参是其他类型变量,且只有一个形参
    Student(int r){
        this->age = r;
        this->num = 1002;
    }
    ~Student(){}
public:
    int age;
    int num;
};
int main(){
    Student s1;
    Student s2(18,1001);
    int a = 10;
    Student s3(a);
    Student s4(s3);
    printf("s1 age:%d, num:%d\n", s1.age, s1.num);
    printf("s2 age:%d, num:%d\n", s2.age, s2.num);
    printf("s3 age:%d, num:%d\n", s3.age, s3.num);
    printf("s2 age:%d, num:%d\n", s4.age, s4.num);
    return 0;
}

执行

  • 默认构造函数和初始化构造函数在定义类的对象,完成对象的初始化工作
  • 复制构造函数用于复制本类的对象
  • 转换构造函数用于将其他类型的变量,隐式转换为本类对象

3 有哪些情况必须用到成员列表初始化?作用是什么?

1) 必须使用成员初始化的四种情况:

  • 当初始化一个引用成员时;
  • 当初始化一个常量成员时;
  • 当调用一个基类的构造函数,而它拥有一组参数时;
  • 当调用一个成员类的构造函数,而它拥有一组参数时;

2) 成员初始化列表做了什么

  • 编译器会一一操作初始化列表,以适当的顺序在构造函数之内安插初始化操作,并且在任何显示用户代码之前;
  •  list中的项目顺序是由类中的成员声明顺序决定的,不是由初始化列表的顺序决定的;

4 如果有一个空类,它会默认添加哪些函数

1) Empty();                          // 缺省构造函数
2) Empty( const Empty& );            // 拷贝构造函数
3) ~Empty();                         // 析构函数
4) Empty& operator=( const Empty& ); // 赋值运算符

5 如何设计一个类计算子类的个数

  • 为类设计一个static静态变量count作为计数器;
  • 类定义结束后初始化count=0;
  • 在构造函数中对count进行+1;
  • 设计拷贝构造函数,在进行拷贝构造函数中进行count +1,操作;
  • 在析构函数中对count进行-1;

6 如何阻止一个类被实例化?有哪些方法

  • 将类定义为抽象基类或者将构造函数声明为private;
  • 不允许类外部创建类对象,只能在类内部创建对象

7 如何禁止程序自动生成拷贝构造函数?

定义一个base类,在base类中将拷贝构造函数和拷贝赋值函数设置成private(或者delete掉),那么派生类中编译器将不会自动生成这两个函数,且由于base类中该函数是私有的(delete的),因此,派生类将阻止编译器执行相关的操作。

8 什么情况会自动生成默认构造函数

1) 带有默认构造函数的类成员对象,如果一个类没有任何构造函数,但它含有一个成员对象,而后者有默认构造函数,那么编译器就为该类合成出一个默认构造函数。不过这个合成操作只有在构造函数真正被需要的时候才会发生;如果一个类A含有多个成员类对象的话,那么类A的每一个构造函数必须调用每一个成员对象的默认构造函数而且必须按照类对象在类A中的声明顺序进行;
2) 带有默认构造函数的基类,如果一个没有任务构造函数的派生类派生自一个带有默认构造函数基类,那么该派生类会合成一个构造函数调用上一层基类的默认构造函数;
3) 带有一个虚函数的类
4) 带有一个虚基类的类

9 什么时候合成构造函数

1) 如果一个类没有任何构造函数,但他含有一个成员对象,该成员对象含有默认构造函数,那么编译器就为该类合成一个默认构造函数,因为不合成一个默认构造函数那么该成员对象的构造函数不能调用;
2) 没有任何构造函数的类派生自一个带有默认构造函数的基类,那么需要为该派生类合成一个构造函数,只有这样基类的构造函数才能被调用;
3) 带有虚函数的类,虚函数的引入需要进入虚表,指向虚表的指针,该指针是在构造函数中初始化的,所以没有构造函数的话该指针无法被初始化;
4) 带有一个虚基类的类。​​​​​​​

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++中拷贝构造函数被调用的时机 的相关文章

随机推荐

  • Python爬虫学了几个月却不敢接单?过来人的经验总结收好!

    前几天有刷到一个提问 爬虫学了几个月了却还是不敢上手去接单 爬虫接单靠不靠谱 有些新手心里会犯嘀咕 怕不小心就踩了红线 作为过来人也接过不少单 来浅聊一下我的经验 这篇所说的经验总结可能更适合爬虫新手 爬虫大佬可以忽略 此篇小结 Pytho
  • git拉取项目、提交代码简单教程

    最近要用HBuilderX做一个uniapp项目 再写一篇git拉项目代码 交代码的文章 虽然和上一篇差不多啦 不过就是上一篇的交代码没有用指令 这一篇就用一下 首先是要装好git和node 可以自行查找教程 应该没什么坑 第一步 新建一个
  • Vue3国际化适配(i18n)的简单使用(非常简单)

    Vue i18n是Vue js的国际化插件 Vue i18n官网 Vue I18n Vue I18n 下载Vue i18n插件 npm方式 npm install vue i18n 9 yarn方式 yarn add vue i18n 9
  • Linux系统编程项目——FTP云盘

    文章目录 一 项目实现功能 二 项目实现思路 三 项目用到的函数 1 access函数 判断文件是否存在的函数 2 chdir函数 进入某个文件夹的函数 3 fgets函数 可以获取空格 且较为安全 四 代码 五 项目总结 遇到的问题 一
  • EtherCAT有什么优点?为何如此受欢迎?

    1 高速以太网 EtherCAT非常快 它使用双绞线或光缆可以在30us内处理1000个分布式I O信号 或在100us内处理100个轴 2 精确同步 最大的优点 具有纳秒级别的同步性 协议栈处理延迟仅需要几纳秒 3 灵活的拓扑结构 Eth
  • 华北电力大学计算机学科排名,2018年华北电力大学世界排名、中国排名、专业排名...

    华北电力大学成立于1958年 原名北京电力学院 该学院于1969年从河北省迁至北京 先后更名为河北电力学院和华北电力学院 1995年 华北电力学院和北京电力经济学院合并为华北电力大学 华北电力大学拥有10所学院 包括电气与电子工程学院 能源
  • mysql主键字符串_MYSQL - 使用字符串作为主键的问题

    SET OLD UNIQUE CHECKS UNIQUE CHECKS UNIQUE CHECKS 0 SET OLD FOREIGN KEY CHECKS FOREIGN KEY CHECKS FOREIGN KEY CHECKS 0 S
  • make[1]: *** No rule to make target ‘.depend.XXXX‘, needed by ‘.XX‘. Stop.解决

    最近在移植uboot支持NANDFLASH时 遇到一个错误 烦了两天 终于找到了 具体报错如下 make 1 No rule to make target depend s3c2440 nand needed by depend Stop
  • 不能建立到远程计算机的连接,因此用于此连接的端口已关闭

    点击跳转 端口 1723 1701
  • Please make sure the TESSDATA_PREFIX environment variable is set to your “tessdata“ directory.

    解决 识别中文 tesseract scan jpg test txt l chi sim eng
  • spring boot jpa之 流式查询 @Query定义查询方法

    一 概述 按照方法名来定义查询方法的形式 只适用于单表的一两个字段 那种复杂的查询 还要自己写sql语句 也就是 Query定义查询方法 以下是 Query和 Param的类路径 import org springframework dat
  • 学习Python爬虫的基础知识和入门教程

    学习Python爬虫需要掌握以下基础知识 1 Python语言基础 学习Python爬虫前需要先学习Python基础语法 数据类型 控制结构等基本概念 2 网络协议 爬虫需要通过网络获取数据 因此需要掌握HTTP协议 TCP IP协议等相关
  • TCP/IP网络模型中数据封装和解封装过程

    当我们在网络上传输数据时 本机会从高层到底层将数据包进行几次封装 解包过程则是相反的顺序 如下图所示 封装 首先在应用层 浏览器会将请求数据封装为HTTP协议数据包 在原本数据包中加入HTTP头 传输层 tcp协议将前一个封装的数据包再次封
  • Fastjson1.0漏洞复现

    服务器kali linux 攻击机win10 搭建好环境之后 测试漏洞 证明存在漏洞 生成payload type com sun org apache xalan internal xsltc trax TemplatesImpl byt
  • 管理node的版本

    使用 nvm 管理node版本 nvm类似 python virtualenv 使用起来更加方便 安装nvm 参见 https www jianshu com p 622ad36ee020 使用cnpm 代替 npm 安装cnpm sudo
  • mysql数据库

    mysql数据库 添加 更新 删除表 删除单条 去重查询 运算符 模糊查询 集合 逻辑 sql gt between 值1 and 值2 is NUll 排序查询 聚合函数 ifNull 列名 默认值 如果列名为空 返回默认值 分组grou
  • chown: /usr/local: Operation not permitted问题解决

    在MAC上安装homebrew事先博客进行安装 根据步骤进行下去 同样在brew update的时候出现报错 Error usr local must be writable 错误 在该文章中也给出解决办法 sudo chown R who
  • 查看python中模块的所有方法

    查看python中模块的所有方法 安装的python模块 现将查看方法总结如下 一 CMD命令行下使用pydoc命令 在命令行下运行 pydoc modules即可查看 二 在python交互解释器中使用help 查看 在交互式解释器中输入
  • 双向带头循环链表的实现

    1 学习第一步 当我们要学习和了解一个事物时 我们要做的第一步便是对这个事物有一个体的的了解 现在我们要学习双向带头循环链表的第一步也是这个 我们现在先来了解一下这种链表的结构 就像该图所呈现的那样 双向循环链表就是长这样 但是你可千万不要
  • c++中拷贝构造函数被调用的时机

    1 c 中拷贝构造函数被调用的时机 拷贝构造函数被调用的几种情况 1 当用类的一个对象去初始化该类的另一个对象时 系统会自动调用拷贝构造函数 2 将一个对象作为实参传递给一个非引用类型的形参 系统会自动调用拷贝构造函数 3 从一个返回类为非