C++拷贝构造函数的几个细节
详解C++中构造函数,拷贝构造函数和赋值函数的区别和实现
详解C++中构造函数,拷贝构造函数和赋值函数的区别和实现C++中⼀般创建对象,拷贝或赋值的⽅式有构造函数,拷贝构造函数,赋值函数这三种⽅法。
下⾯就详细⽐较下三者之间的区别以及它们的具体实现1.构造函数构造函数是⼀种特殊的类成员函数,是当创建⼀个类的对象时,它被调⽤来对类的数据成员进⾏初始化和分配内存。
(构造函数的命名必须和类名完全相同)⾸先说⼀下⼀个C++的空类,编译器会加⼊哪些默认的成员函数默认构造函数和拷贝构造函数析构函数赋值函数(赋值运算符)取值函数**即使程序没定义任何成员,编译器也会插⼊以上的函数!注意:构造函数可以被重载,可以多个,可以带参数;析构函数只有⼀个,不能被重载,不带参数⽽默认构造函数没有参数,它什么也不做。
当没有重载⽆参构造函数时,A a就是通过默认构造函数来创建⼀个对象下⾯代码为构造函数重载的实现<span style="font-size:14px;">class A{int m_i;Public:A(){Cout<<”⽆参构造函数”<<endl;}A(int i):m_i(i) {} //初始化列表}</span>2.拷贝构造函数拷贝构造函数是C++独有的,它是⼀种特殊的构造函数,⽤基于同⼀类的⼀个对象构造和初始化另⼀个对象。
当没有重载拷贝构造函数时,通过默认拷贝构造函数来创建⼀个对象A a;A b(a);A b=a; 都是拷贝构造函数来创建对象b强调:这⾥b对象是不存在的,是⽤a 对象来构造和初始化b的!!先说下什么时候拷贝构造函数会被调⽤:在C++中,3种对象需要复制,此时拷贝构造函数会被调⽤1. 1)⼀个对象以值传递的⽅式传⼊函数体2. 2)⼀个对象以值传递的⽅式从函数返回3. 3)⼀个对象需要通过另⼀个对象进⾏初始化什么时候编译器会⽣成默认的拷贝构造函数:1. 1)如果⽤户没有⾃定义拷贝构造函数,并且在代码中使⽤到了拷贝构造函数,编译器就会⽣成默认的拷贝构造函数。
拷贝构造函数的用法-电脑资料
拷贝构造函数的用法-电脑资料jiu_acm纸上得来终觉浅绝知此事要躬行拷贝构造函数的用法1.拷贝构造函数是与类名相同,其形参是本类的对象的引用,。
2.拷贝构造函数会在以下三种情况下被调用:1).当用类的一个对象去初始化该类的另一个对象时。
2).如果函数的形参是类的对象,调用该函数,将对象作为函数实参传递给函数的形参时。
3).如果函数的返回值是类的对象,函数执行完成,将返回值返回时。
3.浅拷贝的失败例子:1 #include2 #include34 using namespace std;567 class str8 {9 private:10 char *s;11 int len;12 public:13 str()14 {15 len=0;16 s=NULL;17 }18 str(const char *p)19 {20 len=strlen(p);21 s=new char[len+1];22 strcpy(s,p);23 }24 ~str()25 {26 if(s!=NULL)27 {28 delete []s;29 s=NULL;30 }31 }32 };3334 int main()35 {36 str s1("I love you!");37 str s2=s1; //这里会发生错误,电脑资料《拷贝构造函数的用法》(https://www.)。
38 return 0;39 }之所以发生错误是因为两个对象在析构时都要delete那块堆里的内存,但是程序里是浅拷贝,也就是说,s2只拷贝了s1的堆内存的地址,s2的s指针指向s1申请的堆内存,两次delete同一块内存,明显不合法。
故而需要增加自定义拷贝构造函数,即深拷贝。
见于下例:1 str(str &r)2 {3 len=r.len;4 if(len!=0)5 {6 s=new char[len+1];7 strcpy(s,r.s);8 }9 }4.注意:1).在自定义拷贝构造函数后,缺省拷贝构造函数和构造函数失效,构造函数需要自定义。
c++ 复制构造函数 拷贝构造函数
c++ 复制构造函数拷贝构造函数C++中的复制构造函数,也称为拷贝构造函数,是一种特殊的构造函数,它的作用是用一个已经存在的对象去初始化一个新的对象。
当我们没有定义复制构造函数时,C++会自动生成一个默认的复制构造函数,它的实现方法是将一个对象的每个成员变量的值都复制到新对象中。
但是,当对象中存在指针类型的成员变量时,简单的值复制可能会导致内存泄漏等问题。
因此,我们需要手动实现复制构造函数,以确保正确地复制对象。
复制构造函数的定义格式如下:ClassName(const ClassName &obj)其中,ClassName是类名,obj是待复制的对象。
在复制构造函数中,一般需要做以下几个步骤:1. 判断待复制对象和新对象是否是同一个对象,如果是,则不需要复制。
2. 分配内存空间,对新对象进行初始化。
3. 将待复制对象的成员变量值复制到新对象中。
如果存在指针类型的成员变量,则需要进行深拷贝,即重新分配内存空间并将指针指向的值复制到新内存中。
4. 返回新对象。
下面是一个示例代码:```class Person {public:Person() {name = new char[20];age = 0;}Person(const Person &obj) { if (&obj == this) {return;}name = new char[20];strcpy(name, );age = obj.age;}~Person() {delete[] name;}private:char *name;int age;};```在上面的代码中,我们定义了一个包含指针类型成员变量的类Person,并手动实现了复制构造函数。
在复制构造函数中,我们首先判断待复制对象和新对象是否是同一个对象,如果是,则不需要进行复制。
然后,我们重新分配内存空间,将待复制对象的成员变量值复制到新对象中,并对指针类型成员变量进行了深拷贝。
拷贝构造函数被调用的三种情况
拷贝构造函数被调用的三种情况一、引言拷贝构造函数是C++中的一个重要概念,它用于创建一个新对象,该对象与原始对象具有相同的值和属性。
在C++中,拷贝构造函数被广泛应用于各种编程场景中,比如对象作为函数参数传递、对象作为返回值返回等等。
本文将介绍拷贝构造函数被调用的三种情况。
二、第一种情况:使用一个对象初始化另一个对象当使用一个已经存在的对象来初始化另一个新的对象时,就会调用拷贝构造函数。
这通常发生在以下情况下:1. 对象作为函数参数传递当将一个对象作为函数参数传递时,如果该参数没有被声明为引用类型,则会调用拷贝构造函数。
例如:```void func(MyClass obj){// do something}MyClass obj1;func(obj1);```上面代码中,obj1是MyClass类的一个实例化对象,在调用func()函数时将obj1作为参数传递给了该函数。
由于obj1不是引用类型,因此会调用拷贝构造函数来创建一个新的MyClass类的实例化对象,并将其初始化为obj1。
2. 对象作为返回值返回当将一个已经存在的对象作为返回值返回时,也会调用拷贝构造函数。
例如:```MyClass func(){MyClass obj;// do somethingreturn obj;}MyClass obj1 = func();```上面代码中,func()函数返回了一个MyClass类的实例化对象obj。
由于obj是一个局部变量,当函数返回时,其内存空间将被释放。
此时,编译器会调用拷贝构造函数来创建一个新的MyClass类的实例化对象,并将其初始化为obj。
三、第二种情况:使用一个对象初始化另一个对象数组当使用一个已经存在的对象来初始化另一个对象数组时,也会调用拷贝构造函数。
例如:```MyClass obj1;MyClass arr[3] = {obj1, obj1, obj1};```上面代码中,定义了一个MyClass类的实例化对象obj1和一个包含3个元素的MyClass类的对象数组arr。
C++拷贝(复制)构造函数详解
C++拷贝(复制)构造函数详解⼀. 什么是拷贝构造函数⾸先对于普通类型的对象来说,它们之间的复制是很简单的,例如:[c-sharp]1. int a = 100;2. int b = a;⽽类对象与普通对象不同,类对象内部结构⼀般较为复杂,存在各种成员变量。
下⾯看⼀个类对象拷贝的简单例⼦。
[c-sharp]1. #include <iostream>2. using namespace std;3.4. class CExample {5. private:6. int a;7. public:8. //构造函数9. CExample(int b)10. { a = b;}11.12. //⼀般函数13. void Show ()14. {15. cout<<a<<endl;16. }17. };18.19. int main()20. {21. CExample A(100);22. CExample B = A; //注意这⾥的对象初始化要调⽤拷贝构造函数,⽽⾮赋值23. B.Show ();24. return 0;25. }运⾏程序,屏幕输出100。
从以上代码的运⾏结果可以看出,系统为对象 B 分配了内存并完成了与对象 A 的复制过程。
就类对象⽽⾔,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。
下⾯举例说明拷贝构造函数的⼯作过程。
[c-sharp]1. #include <iostream>2. using namespace std;3.4. class CExample {5. private:6. int a;7. public:8. //构造函数9. CExample(int b)10. { a = b;}11.12. //拷贝构造函数13. CExample(const CExample& C)14. {15. a = C.a;16. }17.18. //⼀般函数19. void Show ()20. {21. cout<<a<<endl;22. }23. };24.25. int main()26. {27. CExample A(100);28. CExample B = A; // CExample B(A); 也是⼀样的29. B.Show ();30. return 0;31. }CExample(const CExample& C) 就是我们⾃定义的拷贝构造函数。
C++编程析构函数拷贝构造函数使用示例详解
C++编程析构函数拷贝构造函数使⽤⽰例详解⽬录构造函数析构函数拷贝构造之深拷贝和浅拷贝深浅拷贝区别⾸先定义⼀个类进⾏操作。
class MM{public:protected:int year;string name;}构造函数在类中默认有⼀个⽆参的构造函数默认的构造函数为类名(){};这个构造函数如果直接写了构造函数那么这个构造函数将会没有构造函数class MM{public://MM() {};//⽆参构造函数MM(int year, string name) :year(year), name(name) {};//有参构造函数在定义对象的时候必须传参数,没参数会报错MM(int year, string name){this->name = name;this->year = year;}//这两个是⼀样的MM(int year, string name = "") :year(year) {};//因为string 是缺省的如果写没有构造默认为空就是 MM mm(15);这⾥mm对象year=15 name=“”;//缺省只能左边到右边protected:int year;string name;};析构函数MM(){};就是对构建的对象进⾏销毁析构函数的使⽤是⼀个⾃动调⽤的过程不需要⼈为进⾏,当对象的⽣命周期结束⾃动释放//析构函数需要注意的点1.当对象存在指针的时候使⽤析构函数时,析构函数⾥⾯需要释放指针的指向class MM{public:MM(const char* str){strcpy(this->str, str);}~MM() { delete[] str; };//这⾥需要释放str内存不然析构函数只会释放类不会释放strprotected:int year;string name;char* str;};int main(){MM mm("kkk");return 0;}如果类中没有指针就不⽤在析构函数中去释放指针指向拷贝构造(对对象进⾏赋值)//直接调⽤拷贝构造不调⽤构造函数MM mm(15,"kkk");//拷贝构造的⼆种⽅式对对象进⾏赋值MM mm1(mm);MM mm2 = mm;mm1.printfMM();mm2.printfMM();如果是通过匿名创建时匿名对象调⽤构造函数MM mm3 = MM(16, "jfsdl");mm3.printfMM();然后匿名对象赋值给对象调⽤的是拷贝构造函数拷贝构造之深拷贝和浅拷贝//浅拷贝默认也是浅拷贝就是赋值拷贝MM(const MM&object){this->str = object.str;}//深拷贝//深拷贝就是通过指针申请指向然后进⾏赋值MM(const MM& object){int len = strlen(object.str) + 1;this->str = new char[len];strcpy(str, object.str);}深浅拷贝区别浅拷贝就是进⾏了赋值操作深拷贝是通过申请指针后再进⾏赋值(深拷贝析构函数要释放申请的指针)谢谢⼤家的阅读,如有不⾜请及时指出,万分感激以上就是C++编程析构函数拷贝构造函数使⽤⽰例详解的详细内容,更多关于C++编程析构函数拷贝构造函数的资料请关注其它相关⽂章!。
c++拷贝构造函数(重点在内含指针的浅拷贝和深拷贝)
c++拷贝构造函数(重点在内含指针的浅拷贝和深拷贝)今天同事问了⼀个关于拷贝构造函数的问题,类中包含指针的情况,今天就来说说c++的拷贝构造函数。
c++的拷贝构造函数是构造函数的⼀种,是对类对象的初始化,拷贝构造函数只有⼀个参数就是本类的引⽤。
注意,默认构造函数(即⽆参构造函数)不⼀定存在,但是拷贝构造函数总是会存在。
下⾯是⼀个拷贝构造函数的例⼦。
1 #include<iostream>2using namespace std;3class A{4public:5int a;6 A(int value){7 a = value;8 }9void show(){10 cout<<a<<endl;11 }12 };13int main(){14 A test_a(10);15 test_a.show();1617 A test_b(test_a);18 test_b.show();1920return0;21 }输出结果为:1010如果编写了拷贝构造函数,则默认拷贝构造函数就不存在了。
下⾯是⼀个⾮默认拷贝构造函数的例⼦。
1 #include<iostream>2using namespace std;3class A{4public:5int a;6 A(int value){7 a = value;8 }9 A(A& tmp){10 a = tmp.a;11 cout<<"call copy construct"<<endl;12 }13void show(){14 cout<<a<<endl;15 }16 };17int main(){18 A test_a(10);19 test_a.show();2021 A test_b(test_a);22 test_b.show();2324return0;25 }输出结果为:10call copy construct10拷贝构造函数在以下三种情况下会被调⽤。
C++拷贝构造函数和赋值构造函数
C++拷贝构造函数和赋值构造函数转⾃:⼀、拷贝构造函数int main(int argc, char * argv[]){CExample A;A.Init40);CExample B=A; //把B初始化为A的副本...}B = A ; 此语句的具体过程:⾸先建⽴对象theObjtwo,并调⽤其构造函数,然后成员被拷贝。
语句"CExample B=A;" ⽤ A 初始化 B。
其完成⽅式是内存拷贝,复制所有成员的值。
完成后,A.pBuffer = B.pBuffer, 即它们将指向同样的地⽅,指针虽然复制了,但所指向的空间并没有复制,⽽是由两个对象共⽤了。
这样不符合要求,对象之间不独⽴了,并为空间的删除带来隐患。
所以需要采⽤必要的⼿段(拷贝构造函数)来避免此类情况。
拷贝构造函数的格式为 : 构造函数名(对象的引⽤) 提供了拷贝构造函数后的CExample类定义为:class CExample{public :CExample(){pBuffer=NULL; nSize=0;} //构造函数~CExample(){delete pBuffer;} // 析构函数CExample(const CExample&); //拷贝构造函数void Init(int n){ pBuffer=new char [n]; nSize=n;}private :char *pBuffer; //类的对象中包含指针,指向动态分配的内存资源int nSize;};//拷贝构造函数的定义CExample::CExample(const CExample& RightSides){nSize=RightSides.nSize; //复制常规成员pBuffer=new char [nSize]; //复制指针指向的内容memcpy(pBuffer,RightSides.pBuffer,nSize*sizeof (char ));}这样,定义新对象,并⽤已有对象初始化新对象时,即执⾏语句“CExample B=A; ” 时,CExample(const CExample& RightSides)将被调⽤,⽽已有对象⽤别名RightSides传给构造函数,以⽤来作复制。
c数组拷贝函数
c数组拷贝函数一、函数介绍本文将为大家介绍C语言中的数组拷贝函数,该函数可以用于将一个数组的所有元素拷贝到另一个数组中。
该函数的实现需要考虑到数组类型、数组长度以及内存分配等问题,因此需要注意相关细节。
二、函数原型在开始编写函数之前,我们先来确定一下该函数的原型。
根据需求,我们可以将该函数定义为以下形式:void array_copy(void *src, void *dest, size_t count);其中,src表示源数组的首地址,dest表示目标数组的首地址,count 表示需要拷贝的元素个数。
三、函数实现1. 判断数据类型在开始实现拷贝操作之前,我们需要先判断源数组和目标数组的数据类型是否相同。
如果数据类型不同,则无法进行拷贝操作。
因此,我们需要通过指针类型来判断两个数组是否具有相同的数据类型。
具体代码如下:if (sizeof(*src) != sizeof(*dest)) {printf("Error: Data type of source and destination arrays must be the same.\n");return;}2. 判断数据长度接下来,我们需要判断源数组和目标数组的长度是否相同。
如果两个数组长度不同,则无法进行完全拷贝操作。
因此,在进行拷贝操作之前,我们需要先判断两个数组的长度,并选择较小值作为实际拷贝元素个数。
具体代码如下:size_t len = (count < sizeof(src) / sizeof(*src)) ? count : sizeof(src) / sizeof(*src);3. 内存分配在确定了实际拷贝元素个数之后,我们需要为目标数组分配内存空间。
由于目标数组的长度可能小于源数组的长度,因此我们需要使用动态内存分配函数来为目标数组分配足够的内存空间。
具体代码如下:dest = malloc(len * sizeof(*dest));4. 拷贝操作在完成了内存分配之后,我们可以开始进行拷贝操作了。
c++类的拷贝、赋值与销毁(拷贝构造函数、拷贝赋值运算符和析构函数)
c++类的拷贝、赋值与销毁(拷贝构造函数、拷贝赋值运算符和析构函数)拷贝构造函数如果⼀个构造函数的第⼀个参数是⾃⾝类类型的引⽤,且任何额外参数都有默认值,则此构造函数是拷贝构造函数。
拷贝构造函数第⼀个参数必须是⼀个引⽤类型。
此参数⼏乎总是⼀个const的引⽤。
拷贝构造函数在⼏种情况下都会被隐式地使⽤。
因此,拷贝构造函数通常不应该是explicit的。
合成拷贝构造函数与合成默认构造函数不同,即使我们定义了其他构造函数,编译器也会为我们合成⼀个拷贝构造函数。
对某些类来说,合成拷贝构造函数⽤来阻⽌我们拷贝该类类型的对象。
⽽⼀般情况,合成的拷贝构造函数会将其参数的成员逐个拷贝到正在创建的对象中。
每个成员的类型决定了它如何拷贝。
拷贝初始化直接初始化和拷贝初始化的差异。
string dots(10,','); //直接初始化string s(dots); //直接初始化string s2 = dots; //拷贝初始化当使⽤直接初始化时,我们实际上是要求编译器使⽤普通的函数匹配来选择与我们提供的参数最匹配的构造函数。
当我们使⽤拷贝初始化时,我们要求编译器将右侧运算对象拷贝到正在创建的对象中,如果需要的话还要进⾏类型转换。
拷贝初始化通常使⽤拷贝构造函数来完成。
拷贝初始化是依靠拷贝构造函数或移动构造函数来完成的。
拷贝初始化不仅在我们⽤=定义变量时会发⽣,在下列情况下也会发⽣•将⼀个对象作为实参传递给⼀个⾮引⽤类型的形参。
•从⼀个返回类型为⾮引⽤类型的函数返回⼀个对象。
•⽤花括号列表初始化⼀个数组中的元素或⼀个聚合类中的成员。
参数和返回值拷贝构造函数被⽤来初始化⾮引⽤类类型参数,这⼀特性解释了为什么拷贝构造函数⾃⼰的参数必须是引⽤类型。
如果其参数不是引⽤类型,则调⽤永远也不会成功——为了调⽤拷贝构造函数,我们必须拷贝它的实参,但为了拷贝实参,我们⼜必须调⽤拷贝构造函数,如此⽆限循环。
拷贝初始化的限制vector<int> v1(10); //直接初始化vector<int> v1 = 10; //错误:接受⼤⼩参数的构造函数是explicit的如果我们希望使⽤⼀个explicit构造函数,就必须显式的使⽤:void f(vector<int>); //f的参数进⾏拷贝初始化f(10); //错误:不能⽤⼀个explicit的构造函数拷贝⼀个实参f(vector<int>(10)); //正确:从⼀个int直接构造⼀个临时vector如果我们希望使⽤⼀个explicit构造函数,就必须显式的使⽤:编译器可以绕过拷贝构造函数编译器被允许将下⾯的代码string null_book = "9-999-99999-9";给写成string null_book("9-999-99999-9");//编译器略过了拷贝构造函数。
c++ 拷贝构造函数
c++ 拷贝构造函数一、什么是拷贝构造函数也称为复制构造函数。
复制构造函数参数为类对象本身的引用,根据一个已存在的对象复制出一个新的对象,一般在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中。
先来看一个例子:定义一个Time类,该类有三个公有成员 Hour,Minute,Second。
将该类定义在“Time.h”的头文件里。
建一个main.cpp用来放主函数。
“Time.h”:#include<iostream>usingnamespacestd;classTime{private:int Hour;int Minute;int Second;public:Time(){cout <<"constructor1 is called"<<endl;}Time(int tmphou,int tmpmin,inttmpsec):Hour(tmphou),Minute(tmpmin),Second(tmpsec){ cout <<"constructor2 is called"<<endl;}Time(const Time& tmptime){cout <<"copy constructor is called"<< endl;}~Time(){cout <<"destructor is called"<<endl;}voidprint(){cout << Hour <<' '<< Minute <<' '<< Second << endl;}};“main.cpp”:#include<iostream>#include"Time.h"usingnamespace std;intmain(){Time mytime;Time mytime0(1,2,3);Time mytime1(mytime0);mytime1.print();return0;}最终输出:constructor1 is called constructor2 is calledcopy constructor is called ---destructor is calleddestructor is calleddestructor is called(由于我的拷贝构造函数啥都没写,只有输出,所以并没有真的复制)(该例子也为对象需要通过另外一个对象进行初始化时的构造函数)从以上代码的运行结果可以看出,系统为对象 mytime1 分配了内存并完成了与对象 mytime0 的复制过程。
c++类的拷贝构造函数
c++类的拷贝构造函数C++中的拷贝构造函数是一种特殊类型的构造函数,其作用是在创建对象时,将已经存在的一个对象中的数据成员复制到另一个对象中,通常用于对象间的赋值或传递对象参数。
本文将总结C++中的拷贝构造函数的语法及使用方式,以及相关的注意事项。
```class ClassName{public:ClassName(const ClassName &obj); // 拷贝构造函数};```上述代码中,`ClassName`是类名,`&obj`表示需要拷贝的另一个对象。
在函数体中,通常将需要拷贝的对象的数据成员一一复制到新对象中。
拷贝构造函数通常用于三个场景:1. 对象间赋值```class Student {public:Student(int id, string name);Student(const Student &obj); // 拷贝构造函数private:int id_;string name_;};```如果我们现在定义了一个名为`stu1`的`Student`对象,并将它的值复制给另一个名为`stu2`的`Student`对象:```Student stu1(1, "Tom");Student stu2 = stu1; // 调用拷贝构造函数进行复制```那么,在执行`Student stu2 = stu1`这行代码的时候,会调用拷贝构造函数将`stu1`的数据成员拷贝到`stu2`中。
2. 传递对象参数当我们将一个类的对象作为实参传递给一个函数时,通常是将这个对象的值复制一份作为函数的形参。
这样,在函数内部对形参对象的修改不会影响到实参原有的值。
上述代码中,在调用`print`函数时,拷贝构造函数会被自动调用,将`stu`对象的值复制给`obj`形参。
在函数内部,对`obj`对象的修改不会影响到`stu`对象的值。
3. 返回对象1. 可以定义多个拷贝构造函数如果一个类存在多个类型的构造函数,那么也可以为每一种类型的构造函数定义一个对应的拷贝构造函数,使得在创建对象时可以同时传入不同的值。
c拷贝构造函数和赋值构造函数
c拷贝构造函数和赋值构造函数C++编程语言中,拷贝构造函数和赋值构造函数是非常重要的函数,它们用来实现对象的拷贝和赋值操作,从而使得对象之间的数据和状态得以传递和共享。
下面我们将详细介绍这两种构造函数的定义、实现和应用。
一、拷贝构造函数拷贝构造函数是一种特殊的构造函数,它用于创建一个新的对象,该对象是原对象的一个副本,即它们具有相同的数据成员和属性值。
拷贝构造函数的定义格式如下所示:class ClassName {public:ClassName (const ClassName &obj) {}};在拷贝构造函数中,我们通过引用(const ClassName &obj)的方式来获取原对象的引用,然后将其成员变量值赋值给新对象的成员变量。
需要注意的是,拷贝构造函数不能直接调用,在以下情况下会被自动调用:1. 将一个对象作为函数参数传递给函数时2. 从函数返回对象3. 使用一个对象初始化另一个对象时以下是一个简单的例子,展示了如何实现一个带有拷贝构造函数的类:#include <iostream>using namespace std;class Box {public:int length;int width;int height;Box (int l=0, int w=0, int h=0) : length(l), width(w), height(h) {}Box (const Box &obj) : length(obj.length), width(obj.width), height(obj.height) {}};int main () {Box box1 (10, 5, 3);Box box2 = box1;cout << "Box 1: " << box1.length << ", " << box1.width << ", " << box1.height << endl;cout << "Box 2: " << box2.length << ", " << box2.width << ", " << box2.height << endl;return 0;}在上面的例子中,我们定义了一个拥有三个数据成员的Box类,该类有两个构造函数,一个默认构造函数,一个拷贝构造函数。
C++拷贝构造函数详解
C++拷贝构造函数详解C++拷贝构造函数详解简介拷贝构造函数是C++独有的⼀种特殊的构造函数,以同型对象初始化⾃我对象。
拷贝构造函数是⼀种特殊的构造函数,具有单个形参,该形参(常⽤const修饰)是对该类类型的引⽤。
当定义⼀个新对象并⽤⼀个同类型的对象对它进⾏初始化时,将显⽰使⽤拷贝构造函数。
当该类型的对象传递给函数或从函数返回该类型的对象时,将隐式调⽤拷贝构造函数。
拷贝构造函数拷贝构造函数是⼀种特殊的构造函数,它在创建对象时,是使⽤同⼀类中之前创建的对象来初始化新创建的对象。
拷贝构造函数通常⽤于:通过使⽤另⼀个同类型的对象来初始化新创建的对象。
复制对象把它作为参数传递给函数。
复制对象,并从函数返回这个对象。
如果⽤户没有定义拷贝构造函数,但是调⽤了拷贝构造函数,那么编译器会⾃动⽣成⼀个默认的拷贝构造函数。
但是如果⾃⼰定义了拷贝构造函数,编译器则不在⽣成。
最常见的形式如下:classname (const classname& obj){// code here}下⾯对三种调⽤拷贝构造函数的情况进⾏⼀⼀说明:通过使⽤另⼀个同类型的对象来初始化新创建的对象#include <iostream>using namespace std;class Student {public:Student(); // default构造函数Student(const Student& obj); // 拷贝构造函数int getNumber();private:int number;};// 定义默认构造函数Student::Student(){this->number = 0;cout << "default constructor" << endl;}// 定义拷贝构造函数Student::Student(const Student& obj) {this->number = obj.number;cout << "copy constructor" << endl;}int Student::getNumber() {return this->number;}int main(){Student s1; // 调⽤默认构造函数Student s2(s1); // 调⽤拷贝构造函数Student s3 = s2; // 调⽤拷贝构造函数cout << s1.getNumber() << endl;cout << s2.getNumber() << endl;cout << s3.getNumber();return 0;}/*Outputdefault constructorcopy constructorcopy constructor*/这⾥创建了三个对象,s1 s2 s3。
C++中拷贝构造函数的应用详解
C++中拷贝构造函数的应⽤详解⼀、C++中拷贝构造函数的定义:有⼀个参数的类型是其类类型的构造函数是为拷贝构造函数。
如下所⽰:X::X( const X& x);Y::Y( const Y& y, int =0 );//可以是多参数形式,但其第⼆个即后继参数都有⼀个默认值⼆、拷贝构造函数的应⽤:当⼀个类对象以另⼀个同类实体作为初值时,⼤部分情况下会调⽤拷贝构造函数。
⼀般是这三种具体情况:1.显式地以⼀个类对象作为另⼀个类对象的初值,形如X xx=x;2.当类对象被作为参数交给函数时。
3.当函数返回⼀个类对象时。
后两种情形会产⽣⼀个临时对象。
三、C++中编译器何时合成拷贝构造函数并不是所有未定义有拷贝构造函数的类编译器都会为其合成拷贝构造函数,编译器只有在必要的时候才会为其合成拷贝构造函数。
所谓必要的时刻是指编译器在普通⼿段⽆法完成解决“当⼀个类对象以另⼀个同类实体作为初值”时,才会合成拷贝构造函数。
也就是说,当常规⼿段能解决问题的时候,就没必要动⽤⾮常规⼿段。
如果⼀个类没有定义拷贝构造函数,通常按照“成员逐⼀初始化(Default Memberwise Initialization)”的⼿法来解决“⼀个类对象以另⼀个同类实体作为初值”——也就是说把内建或派⽣的数据成员从某⼀个对象拷贝到另⼀个对象⾝上,如果数据成员是⼀个对象,则递归使⽤“成员逐⼀初始化(Default Memberwise Initialization)”的⼿法。
成员逐⼀初始化(Default Memberwise Initialization)具体的实现⽅式则是位逐次拷贝(Bitwise copy semantics)1。
也就是说在能使⽤这种常规⽅式来解决“⼀个类对象以另⼀个同类实体作为初值”的时候,编译器是不需要合成拷贝构造函数的。
但有些时候常规武器不那么管⽤,我们就得祭出⾮常规武器了 ——拷贝构造函数。
有以下⼏种情况之⼀,位逐次拷贝将不能胜任或者不适合来完成“⼀个类对象以另⼀个同类实体作为初值”的⼯作。
c++中的拷贝构造函数
c++中的拷贝构造函数1拷贝构造函数的作用和定义拷贝构造函数是C++中一个重要的概念,它的作用是在已有对象的基础上创建一个新的对象。
具体来说,拷贝构造函数可以将一个对象中的数据成员值复制到另一个对象中,从而使得新的对象与旧的对象具有相同的数据。
在C++中,拷贝构造函数的函数名是固定的,即它的函数名必须与类名相同,参数是一个指向const的类类型引用,即:```Classname(const Classname&obj);```其中,Classname表示类名,obj表示要拷贝的对象。
2拷贝构造函数的默认实现如果一个类没有提供自己的拷贝构造函数,C++编译器将会为它生成一个默认的拷贝构造函数,该拷贝构造函数执行浅拷贝操作,即只是将对象的成员变量逐个拷贝给新的对象,并不会为新的对象重新分配内存。
例如,下面是一个简单的例子:```include<iostream>using namespace std;class MyClass{public:MyClass(int x){mX=x;}void printX()const{cout<<mX<<endl;} private:int mX;};int main(){MyClass obj1(100);MyClass obj2=obj1;obj1.printX();//输出:100obj2.printX();//输出:100return0;}```在这个例子中,MyClass类没有提供自己的拷贝构造函数,因此编译器会为它生成一个默认的拷贝构造函数。
在执行`MyClass obj2= obj1;`语句时,obj2将会被初始化为obj1的一个拷贝,即它们的数据成员都是相同的。
因此,obj2和obj1的printX()函数输出的结果都是100。
需要注意的是,在默认实现的拷贝构造函数中,如果类中含有指针等动态分配内存的成员变量,拷贝的结果可能是不正确的。
C++中的拷贝构造函数
C++中的拷贝构造函数⼀、拷贝构造函数:格式: A(const A& a);总结:系统为对象B分配了内存并完成了与对象testA的复制过程,就类对象⽽⾔,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。
1.拷贝构造函数的使⽤:A testA;A B = testA;2.析构的先后顺序:程序结束,析构的时候,先析构了B,后析构了testA.⼆、拷贝构造函数的调⽤时机1、当函数的参数为类的对象时;调⽤copy_constructor_fun(A aA)时,会产⽣以下⼏个重要步骤:(1)、A对象传⼊形参时,会先产⽣⼀个临时变量Temp;(2)、然后调⽤拷贝构造函数把A的值给Temp。
(3)、等copy_constructor_fun()指向完毕后,析构掉Temp。
2、函数的返回值是类的对象3、对象需要另外⼀个对象进⾏初始化A testA(100);A B = testA;或者:A C(testA);三、深拷贝和浅拷贝1、默认拷贝构造函数2、浅拷贝简单的值复制,⽐如上⾯⼏个例⼦,都是浅拷贝,默认的拷贝构造函数都是浅拷贝。
3、深拷贝深拷贝主要⽤于类中有指针成员变量时,防⽌析构的时候指针悬挂现象。
因为默认的拷贝构造函数只是简单的值复制,如果存在指针变量,相当于两个指针指向同⼀块内存地址,析构的时候,该块内存地址会被析构两遍,那么当第⼀次被释放之后,后⾯指向该内存的指针就会存在悬挂的现象。
深拷贝主要是为拷贝的类对象中的指针变量开辟新的内存空间,这样释放的时候,就不会出现悬挂现象。
写明显⽰的深拷贝构造函数:四、总结1.为什么拷贝构造函数的参数必须是引⽤传递,⽽不是值传递防⽌递归调⽤。
2、拷贝构造函数的作⽤⽤来复制对象的,使⽤以⼀个对象的实例来初始化这个对象的⼀个新的实例。
3、对⼀个类A,如果⼀个构造函数的第⼀个参数是下列之⼀:1) A&2) const A&3) volatile A&4) const volatile A&且没有其他参数或者其他参数都有默认值,那么这个函数是拷贝构造函数。
C++拷贝函数详解
C++拷贝函数详解1.什么是拷贝构造函数:CA(const CA& C)就是我们自定义的拷贝构造函数。
可见,拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它的唯一的一个参数是本类型的一个引用变量,该参数是const类型,不可变的。
例如:类X的拷贝构造函数的形式为X(X& x)。
当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。
也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用。
以下情况都会调用拷贝构造函数:①程序中需要新建立一个对象,并用另一个同类的对象对它初始化,如前面介绍的那样。
②当函数的参数为类的对象时。
在调用函数时需要将实参对象完整地传递给形参,也就是需要建立一个实参的拷贝,这就是按实参复制一个形参,系统是通过调用复制构造函数来实现的,这样能保证形参具有和实参完全相同的值。
③函数的返回值是类的对象。
在函数调用完毕将返回值带回函数调用处时。
此时需要将函数中的对象复制一个临时对象并传给该函数的调用处。
如Box f( ) //函数f的类型为Box类类型{Box box1(12,15,18);return box1; //返回值是Box类的对象}int main( ){Box box2; //定义Box类的对象box2box2=f( ); //调用f函数,返回Box类的临时对象,并将它赋值给box2}如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。
位拷贝又称浅拷贝,后面将进行说明。
自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。
浅拷贝和深拷贝在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。
这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。
C++类复制构造函数
C++类复制构造函数C++标准中提缺省构造函数、拷贝构造函数、拷贝赋值操作符和析构函数是特殊成员函数。
1.构造函数不能有返回类型,也不能由virtual, const, static 和 volatile来修饰。
但可以由inline来修饰,事实上隐式构造函数就是⽤inline来修饰的。
inline表⽰编译时展开,通常速度块;virtual表⽰运⾏时绑定,通常意味着灵活。
2.类中存在虚函数或者有虚基类的情况下需要显式声明构造函数。
拷贝构造函数也是如此。
3.构造函数是⼀种特殊函数,⽽拷贝构造函数是⼀种特殊的构造函数。
类X的构造函数的第⼀个参数必须为X&,或者const X&;除了第⼀个参数外,构造函数要么不存在其他参数,如果存在其他参数,其他参数必须有默认值。
⼀个类可以有多个拷贝构造函数。
它的形式如下:X::X(X& x)X::X(const X& x)X::X(X& x, int a = 0, int b = 1…)什么时候会调⽤拷贝构造函数?以下三种情况出现时,会调⽤⼀个类的拷贝构造函数:1) ⽤⼀个已经实例化了的该类对象,去实例化该类的另外⼀个对象;2) ⽤该类的对象传值的⽅式作为⼀个函数的参数;3) ⼀个函数返回值为该类的⼀个对象。
⽰例代码如下:#include <iostream>using namespace std;class PairInteger{public:int m_a;int m_b;public:inline PairInteger(){m_a = 1;m_b = 2;}inline PairInteger(int a, int b){m_a = a;m_b = b;}inline PairInteger(const PairInteger& other){m_a = other.m_a;m_b = other.m_b;cout << "copy constructor is called." << endl;}inline PairInteger(PairInteger& other){m_a = other.m_a;m_b = other.m_b;cout << "copy constructor is called." << endl;}void printInfo(){cout << "a = " << m_a << ", b = " << m_b << endl;}};int passObjectByValue(PairInteger pairInteger){return pairInteger.m_a + pairInteger.m_b;}PairInteger returnObject(int a, int b){PairInteger ca(a, b);return ca;}int main(void){PairInteger a;//PairInteger b(); // 不能⽤这种⽅式声明CA的对象bPairInteger c(10, 10);PairInteger d(c); // 情况1) ⽤⼀个已经实例化了的该类对象,去实例化该类的另外⼀个对象int anInt = passObjectByValue(c); // 情况2) ⽤该类的对象传值的⽅式作为⼀个函数的参数PairInteger e = returnObject(11, 11); // 情况3) ⼀个函数返回值为该类的⼀个对象(在dev c++下没有调⽤拷贝构造函数,有待考察) return0;}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C++拷贝构造函数的几个细节
关键字: c++
拷贝构造函数是C++最基础的概念之一,大家自认为对拷贝构造函数了解么?请大家先回答一下三个问题:
1.以下函数哪个是拷贝构造函数,为什么?
1.X::X(const X&);
2.X::X(X);
3.X::X(X&, int a=1);
4.X::X(X&, int a=1, b=2);
2.一个类中可以存在多于一个的拷贝构造函数吗?
3.写出以下程序段的输出结果, 并说明为什么?如果你都能回答无误的话,那么你已经对拷贝构造函数有了相当的了解。
1.#include <iostream></iostream>
2.#include <string></string>
3.
4.struct X {
5. template<typename T>
6. X( T& ) { std::cout << "This is ctor." << std::endl; }
7.
8. template<typename T>
9. X& operator=( T& ) { std::cout << "This is ctor." << std::
endl; }
10.};
11.
12.void main() {
13. X a(5);
14. X b(10.5);
15. X c = a;
16. c = b;
17.}
解答如下:
1. 对于一个类X,如果一个构造函数的第一个参数是下列之一:
a) X&
b) const X&
c) volatile X&
d) const volatile X&
且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数.
1.X::X(const X&); //是拷贝构造函数
2.X::X(X&, int=1); //是拷贝构造函数
2.类中可以存在超过一个拷贝构造函数,
1.class X {
2.public:
3. X(const X&);
4. X(X&); // OK
5.};
注意,如果一个类中只存在一个参数为X&的拷贝构造函数,那么就不能使用const X或volatile X的对象实行拷贝初始化.
1.class X {
2.public:
3. X();
4. X(X&);
5.};
6.
7.const X cx;
8.X x = cx; // error
如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝
构造函数.
这个默认的参数可能为X::X(const X&)或X::X(X&),由编译器根据上下文决定选择哪一个.
默认拷贝构造函数的行为如下:
默认的拷贝构造函数执行的顺序与其他用户定义的构造函数相同,执行先父类后子类的构造.
拷贝构造函数对类中每一个数据成员执行成员拷贝(memberwise Copy)的动作.
a)如果数据成员为某一个类的实例,那么调用此类的拷贝构造函数.
b)如果数据成员是一个数组,对数组的每一个执行按位拷贝.
c)如果数据成员是一个数量,如int,double,那么调用系统内建的赋值运算符
对其进行赋值.
3. 拷贝构造函数不能由成员函数模版生成.
1.struct X {
2. template<typename T>
3. X( const T& ); // NOT copy ctor, T can't be X
4.
5. template<typename T>
6. operator=( const T& ); // NOT copy ass't, T can't be X
7.};
8.
原因很简单, 成员函数模版并不改变语言的规则,而语言的规则说,如果程序需
要一个拷贝构造函数而你没有声明它,那么编译器会为你自动生成一个. 所以
成员函数模版并不会阻止编译器生成拷贝构造函数, 赋值运算符重载也遵循同样的规则.(参见Effective C++ 3edition, Item45)。