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. 说明:虽然复制构造函数属于构造函数的一种,有共同的地方,但是也具有一定的 ...
随机推荐
- boost::function 介绍
本片文章主要介绍boost::function的用法. boost::function 就是一个函数的包装器(function wrapper),用来定义函数对象. 1. 介绍 Boost.Func ...
- 使用Filezilla搭建FTP服务器
1.FTP over TLS is not enabled, users cannot securely http://blog.sina.com.cn/s/blog_4cd978f90102vtwl ...
- Ex 2_34 线性3SAT..._第四次作业
- 编译和运行dubbo-admin管理平台
下载 Github上下载最新的dubbo源码包并解压 修改ZooKeeper相关的配置 打开dubbo-admin/src/main/webapp/WEB-INF下的dubbo.p ...
- 粘包-socketserver实现并发
- 45)django-分页实现
Django提供了一个新的类来帮助你管理分页数据,.它可以接收列表.元组或其它可迭代的对象. 一:常用方法 >>> from django.core.paginator import ...
- python-并发编程之多进程
一.操作系统基础: 进程的概念起源于操作系统,操作系统其它所有概念都是围绕进程来的,所以我们了解进程之前先来了解一下操作系统 操作系统位于计算机硬件与应用软件之间,本质也是一个软件.操作系统由操作系统 ...
- 微信video最上层解决问题
/* http://blog.csdn.net/kepoon/article/details/53608190 */ //x5-video-player-type="h5" x ...
- 【MySql】join操作
飞机票 飞机票 加油 INNER JOIN(内连接,或等值连接):获取两个表中字段匹配关系的记录. LEFT JOIN(左连接):获取左表所有记录,即使右表没有对应匹配的记录. RIGHT JOIN( ...
- pytorch的学习资源
安装:https://github.com/pytorch/pytorch 文档:http://pytorch.org/tutorials/beginner/blitz/tensor_tutorial ...