-
2022-05-18 23:50:28
一、什么是拷贝构造函数
拷贝构造函数,又称复制构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构造及初始化。
其唯一的形参必须是引用,但并不限制为const,一般普遍的会加上const限制。
此函数经常用在函数调用时用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用。
同一个类的对象在内存中有完全相同的结构,如果作为一个整体进行复制或称拷贝是完全可行的。 这个拷贝过程只需要拷贝数据成员,而函数成员是共用的(只有一份拷贝)。在建立对象时可用同一类 的另一个对象来初始化该对象的存储空间,这时所用的构造函数称为拷贝构造函数(Copy Constructor)。
拷贝构造函数的参数一一采用引用。如果把一个真实的类对象作为参数传递到拷贝构造函数,会引起无穷递归 。
在类中如果没有显式给出拷贝构造函数时,则C++编译器自动给出一个缺省的拷贝构造函数。
如果有程序设计者定义的构造函数(包括拷贝构造函数),则按函数重载的规律,调用合适的构造函数。
缺省的拷贝构造函数的特点:按位拷贝。
二、调用拷贝构造函数的情形
在C++中,下面三种对象需要调用拷贝构造函数(有时也称"复制构造函数"):
1) 一个对象作为函数参数,以值传递的方式传入函数体;
class Complex { }; void Fun(Complex c1) { } int main() { Complex c1(1,2); Fun(c1); }
2) 一个对象作为函数返回值,以值传递的方式从函数返回;
Complex Fun() { Complex c(10,20); return c; }
3) 一个对象用于给另外一个对象进行初始化(常称为赋值初始化);
int main() { Complex c1(1,2); Complex c2(c1); Complex c3=c1; }
当对象的成员变量中存在指针变量时,用存在的对象初始化新建对象时指针变量一同初始化,但这时调用一般拷贝构造函数(浅拷贝)会使新对象中的指针指向和初始化对象指针指向一致,那么当用来初始化的对象在释放内存时会释放掉指针指向的内存,而当新创建的对象释放时会出现程序错误,以为这个指针指向的内存被释放了两次。因此我们需要手动提供另一种拷贝构造函数(深拷贝).
三、实现缺省的拷贝构造函数
1.整形数据成员
class Complex { private: int Real; int Image; public: //缺省构造 //Complex() {} //构造函数 Complex(int r=0,int i=0):Real(r),Image(i) { } //拷贝构造函数 不能够定义为const,否则无法对对象成员进行赋值 Complex(const Complex &c):Real(c.Real),Image(c.Image) { } } int main() { Complex c1(1,2); Complex c2(c1);//c1对象初始化c2 Complex c3=c1;//编译器可自动改写为Complex c3(c1); }
class CDate { int year; int month; int day; public: //构造函数 CDate(int y=1,int m=1,int d=1):year(y),month(m),day(d) { } //拷贝构造函数 CDate(const CDate &cd):year(cd.year),month(cd.month),day(cd.day) { } }; int main() { Cdate data(2022,5,12); Cdate datb(data); }
2.char类型数组数据成员
const int len = 20; class CGoods { private char Name[len]; int Amount; float Price; float Total; public: // 构造函数 CGoods() { memset(Name,0,sizeof(Name)); Amount = 0; Price = 0.0; Total = 0.0; } CGoods(const char *name,int amount,int price) { strcpy_s(Name,len,name); Amount = amount; Price= price; Total = Amount * Price; } //拷贝构造函数 CGoods(const CGoos &cg):Amount(cg.Amount),Price(cg.Price),Total(cg.Total) { strcpy_s(Name,len,cg.Nmae); } }; int main() { CGoods c1("wer",12,1235); CGoods c2(c1); }
四、拷贝构造函数必须以引用的形式传递(参数为引用值)。
当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。如果一个对象是被传入自己的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才可以传入它自己的拷贝构造函数,这会导致无限循环直至栈溢出(Stack Overflow)。除了当对象传入函数的时候被隐式调用以外,拷贝构造函数在对象被函数返回的时候也同样的被调用。
更多相关内容 -
C++中拷贝构造函数的总结详解
2021-01-20 06:59:401.什么是拷贝构造函数: 拷贝构造函数嘛,当然就是拷贝和构造了。(其实很多名字,只要静下心来想一想,就真的是顾名思义呀)拷贝又称复制,因此拷贝构造函数又称复制构造函数。百度百科上是这样说的:拷贝构造函数... -
C++中拷贝构造函数的应用
2021-01-20 03:34:21C++中拷贝构造函数的定义 有一个参数的类型是其类类型的构造函数是为拷贝构造函数。如下: X::X( const X& x); Y::Y( const Y& y, int =0 ); //可以是多参数形式,但其第二个即后继参数都有一个默认值 ... -
c++中拷贝构造函数的参数类型必须是引用
2020-12-31 23:44:39原因:如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构造函数。... -
C++中拷贝构造函数的应用详解
2020-12-31 13:50:08一、C++中拷贝构造函数的定义: 有一个参数的类型是其类类型的构造函数是为拷贝构造函数。 如下所示: X::X( const X& x); Y::Y( const Y& y, int =0 ); //可以是多参数形式,但其第二个即后继参数都有一个默认值 ... -
详解C++ 拷贝构造函数
2021-01-19 23:44:42拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于: 通过使用另一个同类型的对象来初始化新创建的对象。 复制对象把它作为参数传递给... -
C++中拷贝构造函数的使用
2012-07-29 08:56:14C++中拷贝构造函数的使用,帮助加深理解。 -
C++中拷贝构造函数与赋值构造函数详解
2022-02-12 10:49:361. 拷贝构造函数 什么时候会调用拷贝构造函数 ? 使用一个已经创建好的对象来初始化一个新的对象。 Student mya("zhang3",22); //如果是在定义一个对象通过另一个对象来初始化,那么会调用拷贝构造函数 ...1. 拷贝构造函数
什么时候会调用拷贝构造函数 ?
使用一个已经创建好的对象来初始化一个新的对象。
Student mya("zhang3",22);
//如果是在定义一个对象通过另一个对象来初始化,那么会调用拷贝构造函数
Student myb(mya);
//等同于Student myb = mya;特点: 值传递的方式给函数参数传值
代码示例如下:
class Student{ public: Student() { cout<<Student()<<endl; } Student(char *name,int age){ this->name = new char[256]; strcpy(this->name,name); this->age = age; cout<<Student(char *name,int age)<<endl; } //如果我们没有自己定义拷贝构造函数,编译器就会帮助我们自动生成默认的拷贝构造函数---浅拷贝--值的拷贝 // Student(Student &other) //Student &other = mya // { // this->name = other.name; // this->age = other.age; // cout<<Student(Student &other)<<endl; // } //自定义深拷贝 --在进行值的拷贝的同时,也要给指针变量申请新的堆空间 Student(const Student &other) //Student &other = mya { //申请堆空间 this->name = new char[256]; //值的拷贝 strcpy(this->name,other.name); this->age = other.age; cout<<Student(Student &other)<<endl; } ~Student(){ //析构函数一般用来 释放 成员的内存空间 delete []name; cout<<~ Student()<<endl; } void show() { cout<<this->name<< <<this->age<<endl; } private: char *name; int age; }; int main() { Student mya("zhang3",22); //如果是在定义一个对象通过另一个对象来初始化,那么会调用拷贝构造函数 Student myb(mya); //Student myb = mya; return 0; }
2. 赋值函数
当一个类的对象对另一个对象进行直接赋值时会调用赋值函数
Data mya;
mya.setName("zhangsan");
Data myb;
//赋值重载
myb = mya; //编译器会转换成 myb.operator=(mya)如果程序员没有自定义赋值运算符函数。系统会调用自动生成的默认赋值函数(如下面代码注释部分)
什么时候需要自定义赋值函数?
如果类定义中存在指针或者引用变量或对象,对象与对象进行赋值时就会出现内存泄漏。
为了防止这种情况发生我们就需要自定义赋值函数。
(我的理解就是 -> 当申请了堆空间的时候 )
代码示例如下
class Data { public: Data(){ name = new char[256]; } ~Data(){ delete[]this->name; } void setName(const char *name) { strcpy(this->name,name); } /* //如果没有自定义赋值函数,系统执行自动生成的默认赋值函数 ---(系统自动生成的赋值函数底层原型) void operator=(Data &ra) //Data &ra = mya { this->name = ra.name; } */ //系统调用默认的赋值函数会造成内存泄漏 /所以我们需要只需要自定义赋值函数 void operator=(Data &ra) //Data &ra = mya { strcpy(this->name, ra.name); } private: char * name; //姓名 }; int main() { Data mya; mya.setName("zhangsan"); Data myb; //赋值重载 myb = mya; //编译器会转换成 myb.operator=(mya) return 0; }
总结:
当我们对两者不够了解时,很容易错写,错用。
拷贝构造函数就是在对象被创建的时候调用的,而赋值函数只能被创建好的对象调用
-
C++中拷贝构造函数的四种调用方式
2020-06-21 22:31:59代码拿着跑一跑就什么都知道了 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string> using namespace std;... 构造函数 */ Student(int age, string name) { this->age.代码
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string> using namespace std; static int i = 0; class Student { private: int age; string name; public: /* 构造函数 */ Student(int age, string name) { this->age = age; this->name = name; cout << "构造函数" << endl; } /* 无参构造函数 */ Student() { cout << "无参构造函数" << endl; } /* 拷贝构造函数 */ Student(const Student & stur) { age = stur.age; name = stur.name; cout << "拷贝构造函数" << endl; } /* 析构函数 */ ~Student() { cout << "析构函数" << endl; } void print() { cout << age << endl; } }; Student fun(int age, string name) { Student stu(age, name); // stu是局部变量,在函数执行完将会进行析构 return stu;//会存在Student temp = stu,在主调函数中如果有变量接受 temp的话就不会立刻释放 } void fun2(const Student stur) { cout << "fun2" << endl; } return 0; }
四种调用方法
int main() { Student stu1(12,"lisi"); #if 0 //第一种调用方式 Student stu2(stu1); //第二种 Student stu3 = stu1; //注:以下方式不行 Student stu3; stu3 = stu1;// 这是先调用无参构造创建,然后再赋值 #endif //第三种作为函数的返回值时会存在 Student temp = stu; fun(10, "张三"); cout << "fun执行完了" << endl;//temp在此之前被析构,相当于匿名对象,使用完就会被析构 #if 0 Student stu4 = fun(11, "王五");//这种情况 stu4= 这一过程没有调用拷贝构造函数,而是直接将temp转正为stu4 cout << "fun执行完了" << endl;//temp被转正为stu4 //第四种,作为函数参数使用时 fun2(stu1);//存在Student stur = stu1 #endif
运行结果
方式1与2
方式3 不用变量接收,执行完以后临时对象立刻被析构
方式3 使用变量接受,临时对象转正
方式4 存在Student stur = stu1
-
详解C++ 拷贝构造函数和赋值运算符
2020-09-01 00:34:48本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数、什么情况下调用赋值运算符。最后,简单的分析了下深拷贝和浅拷贝的问题。有需要的朋友可以看下 -
C++——拷贝构造函数详解
2022-01-13 15:11:02C++——拷贝构造函数1拷贝构造函数的特点:2通过例子引入拷贝构造:3构造对象的时候使用引用返回与不使用引用返回的问题:3.1不使用引用返回3.2引用返回——从已经死亡的地址接收值不牢靠 1拷贝构造函数的特点: ...C++——拷贝构造函数详解
1.拷贝构造函数的特点:
函数名和类型名一样
Object(const Object& obj) { }
上面的形参里面需要加上“&”,目的是为了防止无限的构造,形成死递归。
加上const,目的是常引用,不能改变里面的值
2.通过例子引入拷贝构造:
问:下面的fun函数在调用的过程中创建了几个对象?(答:五个)
加了引用,就会减少对象构建次数(四次)
上图的fun函数中为什么要加const呢?到底加不加const?
不想形参改变实参加const,想让形参改变实参就不加const。取决于我们想不想修改参数。3构造对象的时候使用引用返回与不使用引用返回的问题:
3.1不使用引用返回:
3.2引用返回——从已经死亡的地址接收值不牢靠:
以引用返回就是返回这个对象的地址
所以:对象的生存期不受fun函数的影响,就可以用引用返回4.缺省的拷贝构造和等号运算符重载
当我们不写拷贝构造函数和等号运算符重载,系统会自动生成浅拷贝。
5.深拷贝和浅拷贝的问题
5.1浅拷贝导致的重复析构问题:
浅拷贝就是将seqade内容直接赋值给seqb,解析如下图:
那么seqb.data也只想seqa.data指向的内容时,如果在析构的时候我们析构了seqb,seqb.data所指向的内容就会被释放掉,等到seqa时候的时候,会出现重复析构同一空间而导致出错的问题。5.2浅拷贝会导致内存泄漏的问题:
代码如下图:
内存解析图如下:
6.重写拷贝构造
当我们重写了拷贝构造之后就会把seqa的值赋值给seqb,然后seqb开辟一片和seqa等大小的堆区空间,再把seqa堆区的内容拷贝到seqb中,
7.总结
凡是在类中设计成指针或者设计指向内核态对象,就要写自己的拷贝构造和等号运算符重载。
(指针、文件指针/线程、信号量、互斥量) -
C++拷贝构造函数(深拷贝与浅拷贝)详解
2020-09-05 00:57:16深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝 -
C++中拷贝构造函数被调用的三种情况
2019-10-03 18:51:29构造函数可以有多个,而拷贝构造函数只能有一个,因为拷贝构造函数的参数只能是当前类的一个对象,参数表是固定的,无法重载,若用户没有定义自己的辅助构造函数,系统会自动生成一个复制构造函数(浅拷贝构造函数,... -
详解C++中构造函数,拷贝构造函数和赋值函数的区别和实现
2021-01-01 04:58:33C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数,赋值函数这三种方法。下面就详细比较下三者之间的区别以及它们的具体实现 1.构造函数 构造函数是一种特殊的类成员函数,是当创建一个类的对象时,它... -
C++拷贝构造函数(复制构造函数)详解篇
2021-09-11 16:33:26在C++中,拷贝并没有脱离它本来的含义,只是将这个含义进行了“特化”,是指用已经存在的对象创建出一个新的对象。从本质上讲,对象也是一份数据,因为它会占用内存。 严格来说,对象的创建包括两个阶段.. -
详解C++ 编写String 的构造函数、拷贝构造函数、析构函数和赋值函数
2020-12-31 08:37:14详解C++ 编写String 的构造函数、拷贝构造函数、析构函数和赋值函数 编写类String 的构造函数、析构函数和赋值函数,已知类String 的原型为: class String { public: String(const char *str = NULL); // 普通... -
c/c++拷贝构造函数和关键字explicit详解
2020-12-31 20:02:23关键字explicit 修饰构造方法的关键字,加上了,就告诉编译器,不可以隐式初始化对象;不加就可以隐式初始化对象; 下面的代码是可以正常编译执行的,但是加了关键字explicit,编译就会错我,因为...拷贝构造函数如果 -
C++中拷贝构造函数的定义传参问题
2019-07-05 22:58:22在C++中,我们使用拷贝构造函数来实现对象的复制。我们需要注意的是,在定义拷贝构造函数的时候,传入参数不能是传值参数,例如A(A other)。因为如果是传值函数,就会在拷贝构造函数内将形参复制为实参,而复制的... -
什么时候调用拷贝构造函数
2021-01-20 13:17:40以下几种情况会调用拷贝构造函数 1. 以一个对象初始化另一个对象 2. 函数以某个对象为参数 3. 函数返回某个对象 4. 初始化序列式容器的元素 2. void test2() { Test t1(1,2); Test t2; t2=t1;//调用的不是拷贝构造... -
C++中拷贝构造函数与拷贝赋值操作符
2017-08-22 17:42:25当我们显式或者隐式地对该类型进行拷贝操作时,就会用到该类的拷贝构造函数(copy construction)和拷贝赋值操作符(copy-assignment operator)。 1 拷贝构造函数 如果一个构造函数的第一个参数是自身类类型的... -
c++ 禁止拷贝构造函数
2021-10-09 22:28:17但是最关键的是noncopyable把拷贝构造函数和拷贝赋值函数做成了private的,继承自noncopyable的类在执行拷贝操作时会调用基类的拷贝操作,但是基类的拷贝操作是private的,因此无法调用,引发编译错误。 -
C++“拷贝构造函数”和“重载 = 运算符”
2022-05-04 18:37:17拷贝构造函数和缺省拷贝构造函数 拷贝构造函数 功能介绍 拷贝构造函数是一种特殊的构造函数,作用是用一个已知的对象来初始化一个新创建的同类的对象。 关键字:①新创建的;②同类的; 定义方法 ClassName::... -
C++构造函数: 拷贝构造函数、转换构造函数、初始化构造函数、默认构造函数
2020-07-19 18:18:50C++中的构造函数 C++中的构造函数可以分为4类: (1)默认构造函数。以Student类为例,默认构造函数的原型为 Student();//没有参数 (2)初始化构造函数 Student(int num,int age);//有参数 (3)复制(拷贝)... -
C++ 拷贝构造函数详解
2021-06-14 15:24:36C++ 拷贝构造函数详解 下面的讲解将以C++标准库的string类作为讲解对象,string类:class with pointer member(s) 1、拷贝构造函数和拷贝赋值函数 1.1引入 下面是给出的测试函数,也是我们要能在自己设计的myString... -
为什么C++中的拷贝构造函数的形参不能使用值或者指针传递?
2022-03-21 10:12:10举例详细说明拷贝构造函数为什么不能使用指针传递或者值传递...