C++ 复制构造函数 与 赋值运算符
在C++中,将一个对象赋给另外一个对象,编译器将提供赋值运算符的定义。
有两种情况,下面假设catman是Monster的一个实例
第一种:初始化
Monster golblen= catman;
第二种:普通赋值
Monster golblen;
golblen= catman;
复制构造函数
其中,第一种情况,系统将调用复制构造函数,其原型为
Monster(const Monster& monster);
如果Monster里没有提供该函数,编译器将自动提供,编译器自动提供时
Monster monster3 = monster1;
相当于
Monster monster3;
monster3. name = monster1.name
由于monster3的name实际上共享monster1的name,所以这种复制叫做“浅复制”,两个对象共享同一份成员变量,在析构时会报错。
解决错误的方式是自己定义一个复制构造函数,并且自己为name开辟空间,将monster1的name使用strcpy_s的方式拷贝到自己开辟的空间里
顺带一提,monster2是用new创建的,new出来的对象存活于堆中,其他两个对象存活于栈中,系统只会自动释放栈内空间,而堆内空间需要用户自己维护。
Monster类声明
#pragma once
#include <iostream>; using std::ostream;
using std::cin;
using std::cout;
using std::endl; class Monster { private:
char* name; public:
Monster();
Monster(const char* name);
Monster(const Monster& monster);
~Monster();
friend ostream& operator<<(ostream& os, const Monster& monster);
};
Monster类定义
#include "Monster.h"; Monster::Monster()
{
cout << "默认构造函数执行完毕" << endl;
} Monster::Monster(const char* name)
{
this->name = new char[strlen(name) + ];
strcpy_s(this->name, strlen(name) + , name);
cout << "构造函数执行完毕" << endl;
} //复制构造函数,如果没有定义,编译器将自动提供浅复制方式的复制构造函数
Monster::Monster(const Monster& monster)
{
this->name = new char[strlen(monster.name) + ];
strcpy_s(this->name, strlen(monster.name) + , monster.name);
cout << "复制构造函数执行完毕" << endl;
} Monster::~Monster()
{
cout << name << "has been destroyed." << endl;
delete[] name;
}
ostream& operator<<(ostream& os, const Monster& monster)
{
return os << monster.name;
} int main(void)
{
{
Monster monster1("Golblen");
cout << "monster1: " << monster1 << " online" << endl; //下面这种初始化方式,将会调用复制构造函数
Monster monster2 = monster1;
cout << "monster2: " << monster2 << " online" << endl; Monster monster3;
monster3 = monster1;
cout << "monster3: " << monster2 << " online" << endl;
}
cin.get();
return ;
}
运行结果

报错了,看来赋值的时候,并没有调用自定义的复制构造函数,所以释放name时出错了
赋值运算符
解决上面报错的问题,自需要增加一个成员函数,
函数原型
Monster& operator=(const Monster& monstere);
函数定义
Monster& Monster::operator=(const Monster& monster)
{
if (this == &monster)
{
return *this;
}
delete[] this->name;
int length = strlen(monster.name);
name = new char[length+];
strcpy_s(name, length + , monster.name);
cout << "赋值运算符调用完毕" << endl;
return *this;
}
定义赋值运算符时,必须要做的三件事情:
1.由于目标对象已经引用了之前分配的数据,所以一定要使用delete[]来释放这些数据,否则将出现内存泄漏
2.函数应当避免将对象赋给自身,否则做第1步操作释放数据时,会将对象的数据也释放掉
3.函数应当返回一个指向当前对象的调用
另外,赋值运算符只能由类成员函数重载,为什么呢 (见https://bbs.csdn.net/topics/392049284?page=1 )
1:对于赋值操作符(=)--比较特别,因为任何类如果不提供显示的拷贝赋值(即重载=),则编译器会隐式地提供一个。这样的话,如果你再通过友元声明,进行全局的定义会造成调用二义性(即使允许,编译也会出错)
2:对于所有楼主提到的操作符(=,[],(),->),只能声明为成员函数是为了避免不合法的书写通过编译(这是推测出的原因,更深层的可能要研究 C++ 的设计了)
C++ 复制构造函数 与 赋值运算符的更多相关文章
- C++类的复制构造函数和赋值运算符
前言: C++面向对象的编程过程中,凡是在类中运用到动态内存分配的时候总是会写一个显示的复制构造函数和赋值重载运算符,本文将结合C++ Primer Plus一书的内容分析下原因: 一.在C++编程中 ...
- C++学习之路(五):复制构造函数与赋值运算符重载
之前没有细想过两者的区别,今天对此进行简要记录,后续完善补充. 复制构造函数是在类对象被创建时调用的,但是赋值运算符是被已经存在的对象调用完成赋值操作. 复制构造函数只在对象实例化时才被调用,即在复制 ...
- C++中复制构造函数与重载赋值操作符总结
前言 这篇文章将对C++中复制构造函数和重载赋值操作符进行总结,包括以下内容: 1.复制构造函数和重载赋值操作符的定义: 2.复制构造函数和重载赋值操作符的调用时机: 3.复制构造函数和重载赋值操作符 ...
- C++:复制构造函数在什么时候被调用?
这个问题不是疑问了,查了一下国外网站,总结一下.假设Person是一个类,复制构造函数的调用会在以下几种情况下发生: 1.对象在创建时使用其他的对象初始化 Person p(q); //此时复制构造函 ...
- C++中复制构造函数与重载赋值操作符
我们都知道,在C++中建立一个类,这个类中肯定会包括构造函数.析构函数.复制构造函数和重载赋值操作:即使在你没有明确定义的情况下,编译器也会给你生成这样的四个函数.例如以下类: class CTe ...
- 剑指offer:赋值运算符函数和复制构造函数
赋值运算符函数 对于定义一个赋值运算符函数时,需要注意一下几点: (1)函数的返回类型必须是一个引用,因为只有返回引用,才可以连续赋值 (2)传入的参数声明为常量引用,可以提高代码效率,同时赋值运算函 ...
- C++ 拷贝构造函数和赋值运算符
本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义 ...
- c++的复制构造函数
在C++中,下面三种对象需要调用拷贝构造函数(有时也称“复制构造函数”): 1) 一个对象作为函数参数,以值传递的方式传入函数体: 2) 一个对象作为函数返回值,以值传递的方式从函数返回: 3) 一个 ...
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
一.本文目的与说明 1. 本文目的:理清在各种继承时,构造函数.复制构造函数.赋值操作符.析构函数的执行顺序和执行内容. 2. 说明:虽然复制构造函数属于构造函数的一种,有共同的地方,但是也具有一定的 ...
随机推荐
- Shell-自动建立全国城市
Code: #!/bin/bash function mkdirFun() { if [ ! -d $1 ];then mkdir -p $1 fi } filename=city1.txt date ...
- 虚拟机CentOS7下NAT模式的网络配置
NAT模式 就是让Guest OS借助NAT(网络地址交换)功能,通过Host OS所在的网络来访问公网.也就是说,使用NAT模式可以实现Guest OS轻松访问互联网,可以访问宿主计算机所在网络的其 ...
- Linux电源管理(7)_Wakeup events framework【转】
转自:http://www.wowotech.net/pm_subsystem/wakeup_events_framework.html 1. 前言 本文继续“Linux电源管理(6)_Generi ...
- python下载mp4 同步和异步下载支持断点续下
Range 用于请求头中,指定第一个字节的位置和最后一个字节的位置,一般格式: Range:(unit=first byte pos)-[last byte pos] Range 头部的格式有以下几种 ...
- 华为QUIDWAY系列路由器的负载均衡配置
作者:邓聪聪 华为系列路由器的负载均衡NQA联动侦测配置案例: 需求:该局域网,IP地址(末位奇数)走联通,IP地址(末位偶数)走电信当某个运营商不可达时,自动切换.通过NQA来确定运营商是否可达., ...
- SharePoint 2013 错误 0x800700DF 文件大小超出允许的限制,无法保存
问题描述: 利用资源管理员往SharePoint 2013文档库里复制文件时,报错了. 错误 0x800700DF︰ 文件大小超过了允许的限制,无法保存. 解决方法: 解决方法,可以修改本地电脑注册表 ...
- hue报错StructuredException: timed out (code THRIFTSOCKET): None的处理
通过hue的web界面进行hive的sql查询,无法显示结果并报错timeout 报错如下:[28/Jul/2017 11:23:29 +0800] decorators ERROR error ru ...
- MySQL 索引原理相关文章
CSDN的整理: http://bbs.csdn.net/topics/392265880 引擎在磁盘中存储顺序的图解: http://blog.csdn.net/php_lzr/article/de ...
- Windows下安装Confluence并破解汉化
注:本文来源于<Windows下安装Confluence并破解汉化> 一.事前准备 1:JDK下载并安装:jdk-6u45-windows-i586.exe 2:MySQL JDBC连接驱 ...
- Confluence 6 导入一个文本文件
Confluence 允许你从 Confluence 服务器上的一个目录中导入一个文本文件,然后将这个文本文件转换为 Confluence 的页面.每一个文本文件将会在 Confluence 中创建一 ...