C++拷贝构造函数的调用时机
一、拷贝构造函数调用的时机
当以拷贝的方式初始化对象时会调用拷贝构造函数,这里需要注意两个关键点,分别是以拷贝的方式
和初始化对象
1. 初始化对象
初始化对象是指,为对象分配内存后第一次向内存中填充数据,这个过程会调用构造函数,对象被创建后必须立即初始化。也就是说只要创建对象就会调用构造函数。
2.初始化和赋值的区别
初始化和赋值都是将数据写入内存中,从表面看,初始化在很多时候都是以复制的方式来实现的,很容易引起混淆。在定义的同时进行复制叫做初始化,定义完成以后再赋值(不管定义的时候有没有赋值)就叫做赋值。初始化只能由一次,赋值可以由很多次。具体可以看下面的示例。
int a = 100; //以赋值的方式初始化
a = 200; //赋值
a = 300; //赋值
int b; //默认初始化
b = 29; //赋值
b = 39; //赋值
对于基本的数据类型,我们很少会区分初始化和赋值,即使是混淆了,也不会出现什么错误。但是对于类,他们的区别就非常重要了,因为初始化时会调用构造函数(以拷贝的方式初始化时会调用拷贝构造函数),而赋值时会调用重载过的赋值运算符。
二、拷贝构造函数和普通构造函数调用的例子
#include<iostream>
#include<string>
using namespace std;
class Student {
public:
Student(string name = "", int age = 0); //普通构造函数
Student(const Student &Stu); //拷贝构造函数
Student& operator=(const Student &Stu); // 重载 = 运算符
void display();
private:
string m_name;
int m_age;
};
//普通构造函数
Student::Student(string name , int age )
{
m_name = name;
m_age = age;
}
//拷贝构造函数
Student::Student(const Student &Stu)
{
this->m_name = Stu.m_name;
this->m_age = Stu.m_age;
cout << "Copy constructor was called." << endl;
}
// 重载 = 运算符
Student& Student:: operator=(const Student &Stu)
{
this->m_name = Stu.m_name;
this->m_age = Stu.m_age;
cout << "operator=() was called." << endl;
return *this;
}
void Student::display()
{
cout << m_age << " " << m_age << endl;
}
int main()
{
Student stu1("Xiao Ming", 18); // 调用普通构造函数
Student stu2("Xiao Wang", 18); // 调用普通构造函数
Student stu3 = stu1; // 调用拷贝构造函数
stu3 = stu2; //调用operator=()
Student stu4(stu1); // 调用拷贝构造函数
Student stu5; // 调用普通构造函数
stu5 = stu2; //调用operator=()
return 0;
}
/*
输出:
Copy constructor was called.
operator=() was called.
Copy constructor was called.
operator=() was called.
*/
三、以拷贝的方式初始化对象
1. 初始化对象时会调用构造函数,不同的初始化方式会调用不同的构造函数:
- 如果用传递进来的实参初始化对象,那么会调用普通的构造函数。
- 如果用现有对象的数据来初始化对象,就会调用拷贝构造函数,这就是以拷贝的方式初始化对象。
2. 以拷贝的方式来初始化对象的几种情况:
将其它对象作为实参。
Student stu1("Xiao Ming", 18); // 普通初始化
Student stu4(stu1); // 以拷贝的方式进行初始化
/* 即使我们不在类中显示定义拷贝构造函数,这种初始化方式也是有效的,编译器会生成默认的拷贝构造函数 */
在创建对象的同时赋值。
Student stu1("Xiao Ming", 18); // 普通初始化
Student stu3 = stu1; // 以拷贝的方式进行初始化
/* 这是最常见的一种以拷贝的方式初始化对象的情况 */
函数的形参为类类型。
如果函数的形参为类类型(对象),那么调用函数时要将另外一个对象作为实参传递进来赋值给形参,这也是以拷贝的方式初始化形参对象,如下所示。
void func(Student s){
//TODO:
}
Student stu1("Xiao Ming", 18); // 普通初始化
func(stu1); //以拷贝的方式初始化 /* func() 函数有一个 Student 类型的形参 s,将实参 stu 传递给形参 s 就是以拷贝的方式初始化的过程。 */
函数返回值为类类型(与编译器有关不绝对)
当函数的返回值为类类型时,return 语句会返回一个对象,不过为了防止局部对象被销毁,也为了防止通过返回值修改原来的局部对象,编译器并不会直接返回这个对象,而是根据这个对象先创建出一个临时对象(匿名对象),再将这个临时对象返回。而创建临时对象的过程,就是以拷贝的方式进行的,会调用拷贝构造函数,如下所示。
Student func(){
Student stu1("Xiao Ming", 18); // 普通初始化
return stu1;
}
Student stu = func();
C++拷贝构造函数的调用时机的更多相关文章
- 【校招面试 之 C/C++】第4题 拷贝构造函数被调用的3个时机
1.被调用的3个时机: (1)直接初始化或拷贝初始化: (2)将一个对象作为一个实参传递,形参采用非指针或非引用的对象进行接收时(指针即指向了同一块空间,并未实现拷贝:而引用就是实参本身): (3)函 ...
- C++拷贝构造函数被调用的时机
拷贝构造函数调用的几种情况: 当用类的一个对象去初始化该类的另一个对象(或引用)时系统自动调用拷贝构造函数实现拷贝赋值. 若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数.( ...
- 【转】C++的拷贝构造函数深度解读,值得一看
建议看原帖 地址:http://blog.csdn.net/lwbeyond/article/details/6202256 一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很 ...
- C++拷贝构造函数详解(转载)
一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员 ...
- 【转】 c++拷贝构造函数(深拷贝,浅拷贝)详解
c++拷贝构造函数(深拷贝,浅拷贝)详解 2013-11-05 20:30:29 分类: C/C++ 原文地址:http://blog.chinaunix.net/uid-28977986-id-3 ...
- [016]转--C++拷贝构造函数详解
一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员 ...
- C++拷贝构造函数详解 转
一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: [c-sharp] view plaincopy int a = 100; int b = a; 而类对象与普通 ...
- c++拷贝构造函数(深拷贝,浅拷贝)详解
一.什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: ; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量. 下面 ...
- C++拷贝构造函数详解
转自:http://blog.csdn.net/lwbeyond/article/details/6202256 对于一个空类,编译器默认生成四个成员函数:默认构造函数.析构函数.拷贝构造函数.赋值函 ...
随机推荐
- rac添加新节点的步骤与方法2
上一篇文章,把节点删除了.这次新增加一个节点 .新增加的节点是host03.如下: #Public IP192.168.16.45 racdb1192.168.16.46 racdb2192.168. ...
- MP实战系列(五)之封装方法讲解
mybatis plus封装的方法怎么用?以及它们对应的sql是那些sql?及其什么情况用? 这些需要说下,以下我将会将我常用的说下,不是常用的,可能提以下或者不提. 根据主键查询 UserEntit ...
- centos 6.5 gogs迁移外部仓库报错
安装gogs git软件后,使用迁移外部仓库功能,提示“你没有获得导入本地仓库的权限”,发现是因为使用的ssh的链接进行导入 目前gogs咱不支持,随后使用github的https链接导入,依然报错 ...
- Python基础(6)——装饰器
装饰器: def w1(func): def inner(): # 验证1 # 验证2 # 验证3 return func() return inner @w1 def f1(): print 'f1 ...
- Python基础(5)——函数
函数 定义 #函数定义 def calc(x,y): res = x**y return res #返回函数执行结果 calc() #调用函数 关键参数 正常情况下,给函数传参数要按顺序,不想按顺序就 ...
- Ubuntu下禁止自动打开U盘等设备
打开终端 禁止自动挂载: $ gsettings set org.gnome.desktop.media-handling automount false 禁止自动挂载并打开 $ gsettings ...
- Android学习之Button按钮在程序运行时全部变大写的处理
问题: 在layout布局文件中,我们命名的按钮名称是“button1”,程序运行过后,在app上显示出来的是“BUTTON1”,先看源代码和效果: 按钮源代码: 运行效果: 解决办法: 方法一: 在 ...
- GIT 安装、创建版本库
在Linux上安装Git 首先,你可以试着输入git,看看系统有没有安装Git: $ git The program 'git' is currently not installed. You can ...
- BZOJ3720 Gty的妹子树 询问分块、主席树
传送门 学到了询问分块的科技-- 对于修改操作,每发生了\(S\)次修改就重构整棵树,小于\(S\)次的修改操作丢到一个队列里面. 对于每一次查询操作,先在主席树上查询当前子树内部大于\(k\)的节点 ...
- python第二周。2019.4.13
1, 我绘制大蟒蛇就是..保存也对着呢,你要是打开文件的话,先闪个黑屏,再闪个白屏..自动退出,然后啥都没了. 我觉得是我代码编错了...再来一遍! 这次到可以,但是这个大蟒蛇好像没有回头... 刚才 ...