C++构造函数、复制构造函数和析构函数专题(修订版)
- 格式:pdf
- 大小:731.47 KB
- 文档页数:15
含有指针变量的类需要重写拷贝构造函数,拷贝赋值函数,析构函数编译器⾃带拷贝构造(ctor)和拷贝赋值函数(operator =),但是对于成员变量含有指针的类,其不能使⽤默认的拷贝赋值函数。
因为使⽤默认的,会直接将指针指向的地址进⾏赋值 (浅拷贝,共享内存,共指⼀个对象),⽽不是分配⼀块内存,具有相同的数值 (深拷贝,独⽴,两个对象)。
浅拷贝容易造成dangling pointer。
⽤⼀个例⼦来展⽰:1 #ifndef __MYSTRING__2#define __MYSTRING__34class String{5public:6 String(const char* cstr=0);7 String(const String& str); // 拷贝构造8 String& operator= (const String& str); // 拷贝赋值9 ~String();10char* get_c_str const(){11return m_data;12 }13private:14char* m_data; // 带指针成员的类:⼀定要注意拷贝赋值,拷贝构造,析构15// String的底部通过char实现,在外部表现为string16 };1718 inline String::String ( const char* cstr=0 ){19if(cstr){20 m_data=new char[strlen(cstr)+1];21 strcpy(m_data,cstr); // char * strcpy ( char * destination, const char * source );22 }23else{ // 考虑cstr=0;24 m_data=new char[1];25 m_data[0]='\0';26 }27 }2829 inline String::String(const String& str){30 m_data=new char[strlen(str.get_c_str())+1];31 strcpy(m_data,str.m_data);32 }3334 inline String::~String(){35delete[] m_data;36 }3738 inline String& String::operator=(const String& str){39if(this==&str){ // self assignment :⾃我检验(如果没有进⾏这样的处理,在⾃我赋值会产⽣严重的错误)40return *this;41 }42// 构造函数是第⼀次,因此不需要删除,但是赋值需要先进⾏delete43delete[] m_data; // 先删除,重新分配⼀样⼤⼩!44 m_data=new char[strlen(str.get_c_str())+1];45 strcpy(m_data,str.m_data);46return *this; // 其实不⽤返回*this也可以,因为已经实现了修改,但是这样有⼀个好处可以实现 a=b=c;(因为返回的类型继续⽀持=)47 }4849// 调⽤形式: cout << String() ; 第⼀个参数为 << 左边,第⼆个参数为 << 右侧;返回ostream 可以实现 cout << a << b ;50 ostream& operator<<(ostream& os,const String& str){51 os<<str.get_c_str();52return os;53 }5455#endif。
详解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)如果⽤户没有⾃定义拷贝构造函数,并且在代码中使⽤到了拷贝构造函数,编译器就会⽣成默认的拷贝构造函数。
C++_构造函数与析构函数构造函数与析构函数1 构造函数1.1 构造函数具有⼀些特殊的性质1.2 定义构造函数的⼀般形式1.3 利⽤构造函数创建对象2 成员初始化表3 缺省参数的构造函数4 重载构造函数5 拷贝构造函数5.1 ⾃定义拷贝构造函数5.2 缺省的拷贝构造函数5.3 调⽤拷贝构造函数的三种情况5.4 浅拷贝和深拷贝6 析构函数7 调⽤构造函数和析构函数的顺序8 对象的⽣存期构造函数和析构函数都是类的成员函数,但它们都是特殊的成员函数,执⾏特殊的功能,不⽤调⽤便⾃动执⾏,⽽且这些函数的名字与类的名字有关。
C++语⾔中有⼀些成员函数性质是特殊的,这些成员函数负责对象的建⽴、删除。
这些函数的特殊性在于可以由编译器⾃动地隐含调⽤,其中⼀些函数调⽤格式采⽤运算符函数重载的语法。
C++引进⼀个⾃动完成对象初始化过程的机制,这就是类的构造函数。
对象的初始化1. 数据成员是不能在声明类时初始化2. 类型对象的初始化⽅法:1. 调⽤对外接⼝(public成员函数)实现:声明类→定义对象→调⽤接⼝给成员赋值2. 应⽤构造函数(constructor)实现:声明类→定义对象→同时给成员赋值1. 构造函数构造函数是⼀种特殊的成员函数,它主要⽤于为对象分配空间,进⾏初始化。
1.1 构造函数具有⼀些特殊的性质:(1) 构造函数的名字必须与类名相同。
(2) 构造函数可以有任意类型的参数,但不能指定返回类型。
它有隐含的返回值,该值由系统内部使⽤。
(3) 构造函数是特殊的成员函数,函数体可写在类体内,也可写在类体外。
(4) 构造函数可以重载,即⼀个类中可以定义多个参数个数或参数类型不同的构造函数。
构造函数是不能继承(5) 构造函数被声明为公有函数,但它不能像其他成员函数那样被显式地调⽤,它是在定义对象的同时被调⽤的。
(6) 在声明类时如果没有定义类的构造函数,编译系统就会在编译时⾃动⽣成⼀个默认形式的构造函数,(7) 默认构造函数是构造对象时不提供参数的构造函数。
C++试题(含答案)一、选择题1、下列的各类函数中,不是类的成员函数()。
A) 构造函数B) 析构函数C) 友元函数D) 拷贝初始化构造函数2、已知: int n=10;下列表示引用的方法中,正确的是()。
A) int &r;B) int &r=10;C) int &r=n;D) int *r=&n;3、下列关于析构函数的说法,正确的是()A) 其名与类名完全相同B) 返回类型是void类型C) 函数体中必须有delete语句D) 无形参,不可重载4、已知函数原型:void fun(int a,int b=7,char z='*'); 则下面函数调用中不合法的为()。
A) fun(5); B) fun(5,8); C) fun(5,'#'); D) fun(0,0,'*');;5、类A是类B的友元,类B是类C的友元,则以下说法正确的是()。
A) 类B是类A的友元B) 类C是类A的友元C) 类A是类C的友元D) 以上都不对6、关于对象成员的构造函数的调用顺序,说法正确的是()。
A)与它们在类中说明顺序相同B)与析构函数的调用顺序相同C)与它们在成员初始化列表中给出的顺序相同D)以上说法都不对7、以下关于内联函数的说法正确的是()A)类的内联函数必须在类体外用关键字inline定义B)类的内联函数必须在类体内定义C)编译时将内联函数的目标代码插入每个调用该函数的地方D)运行时将内联函数的目标代码插入每个调用该函数的地方8、在有同名全局变量和局部变量时,可以用()提供对全局变量的访问。
A)类运算符B)域运算符C)重载D)引用9、假定x为一个类,执行X a[3],*p[2];语句时会自动调用该类的构造函数()次。
A)2 B)3 C)4 D)510、下列关于new运算符的描述中,错误的是( )。
A) 可以new运算符来动态创建对象和对象数组B) 使用new运算符创建的对象或对象数组,可以使用运算符delete删除C) 使用new运算符创建对象时要调用构造函数D) 使用new运算符调用对象数组时不允许指定初始值11、下面对静态数据成员的描述中,正确的是()A)类的每个对象都有自己的静态数据成员B)静态数据成员是类的所有对象共享的数据C)类的不同对象有不同的静态数据成员值D)静态数据成员不能通过类的对象调用12、如果一个类至少有一个纯虚函数,那么就称该类为()。
C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执⾏顺序和执⾏内容⼀、本⽂⽬的与说明1. 本⽂⽬的:理清在各种继承时,构造函数、复制构造函数、赋值操作符、析构函数的执⾏顺序和执⾏内容。
2. 说明:虽然复制构造函数属于构造函数的⼀种,有共同的地⽅,但是也具有⼀定的特殊性,所以在总结它的性质时将它单独列出来了。
3. 单继承、多继承、虚继承,既然都属于继承,那么虽然有⼀定的区别,但还是相同点⽐较多。
如果放在⼀块讲,但为了将内容制作成递进的,就分开了,对相同点进⾏重复,(⼤量的复制粘贴哈),但在不同点进⾏了标注。
注意:三块内容是逐步递进的如果你懂虚函数,那么单继承和多继承那块你就可以不看;如果你懂多继承,那单继承你就不要看了,⾄于虚继承就等你懂虚继承再回来看吧;如果你只懂单继承,那你就只看单继承就好。
⼆、基本知识1. 对于⼀个空类,例如:class EmptyClass{};虽然你没有声明任何函数,但是编译器会⾃动为你提供上⾯这四个⽅法。
class EmptyClass {public:EmptyClass(); // 默认构造函数EmptyClass(const EmptyClass &rhs); // 复制构造函数~EmptyClass(); // 析构函数EmptyClass& operator=(const EmptyClass &rhs); // 赋值运算符}对于这四个⽅法的任何⼀个,你的类如果没有声明,那么编译器就会⾃动为你对应的提供⼀个默认的(注意合成默认构造函数是⽤于没有编写构造函数编译器才会合成默认构造函数,其中复制构造函数也是构造函数)。
(在《C++ primer》中,这个编译器⾃动提供的版本叫做“合成的***”,例如合成的复制构造函数)当然如果你显式声明了,编译器就不会再提供相应的⽅法。
2. 合成的默认构造函数执⾏内容:如果有⽗类,就先调⽤⽗类的默认构造函数。
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) 就是我们⾃定义的拷贝构造函数。
1.调用所有虚基类的构造函数,从左到右,从最深到最浅:o如果该类被列于成员初始化列表中,任何明确明确指定的参数,都应该被传递过来。
若没有列入成员初始化列表中,虚基类的一个默认构造函数被调用(有的话)。
o此外,要保证虚基类的偏移量在执行期可存取,对于使用vbptr来实现虚基类的编译器来说,满足这点要求就是对vbptr的初始化。
o然而,只有在类对象代表着“most-derived class”时,这些构造函数才可能会被调用。
一些支持这个行为的代码会被放进去2(直观点说就是,虚基类的构造由最外层类控制)。
2.调用所有基类构造函数,依声明顺序:o如果该基类被列入了成员初始化队列,那么所有明确指定的参数,应该被传递过来。
o没有列入的话,那么调用其默认构造函数,如果有的话。
o如果该基类是第二顺位或之后的基类,this 指针必须被调整。
3.正确初始化vptr,如果有的话。
4.调用没有出现在初始化成员列表中的member object的默认构造函数,如果有的话。
5.记录在成员初始化队列中的数据成员初始化操作以声明的顺序被放进构造函数中。
∙什么都不做,采用编译器提供默认行为(bitwise copy或者由编译器合成一个)。
∙自己提供一个赋值运算符操作。
∙明确拒绝将一个对象指定给另一个对象。
对于第三点,只要将赋值操作符声明为private,且不定义它就可以了。
对于第二点,只有在第一点的行为不安全或不正确,或你特别想往其中插入点东西的时候。
以下四种情况copy assignment operator(还是用它的英文名,感觉顺畅点),不具有bitwise copy语意,也就是说这些情况下,编译器要合成copy assignment operator 而不能依靠bitwise copy来完成赋值操作,这四种情况与构造函数、拷贝构造函数的情况类似,原因可以参考它们的。
四种情况如下:∙类包含有定义了copy assignment operator的class object成员。
C语言里面构造函数和析构函数的运用办法C语言里面构造函数和析构函数的运用办法摘要:构造函数与析构函数是一个类中看似较为简单的两类函数,但在实际运用过程中总会出现一些意想不到的运行错误。
本文将较系统的介绍构造函数与析构函数的原理及在C#中的运用,以及在使用过程中需要注意的若干事项。
关键字:构造函数;析构函数;垃圾回收器;非托管资源;托管资源一.构造函数与析构函数的原理作为比C更先进的语言,C#提供了更好的机制来增强程序的安全性。
C#编译器具有严格的类型安全检查功能,它几乎能找出程序中所有的语法问题,这的确帮了程序员的大忙。
但是程序通过了编译检查并不表示错误已经不存在了,在“错误”的大家庭里,“语法错误”的地位只能算是冰山一角。
级别高的错误通常隐藏得很深,不容易发现。
根据经验,不少难以察觉的程序错误是由于变量没有被正确初始化或清除造成的,而初始化和清除工作很容易被人遗忘。
微软利用面向对象的概念在设计C#语言时充分考虑了这个问题并很好地予以解决:把对象的初始化工作放在构造函数中,把清除工作放在析构函数中。
当对象被创建时,构造函数被自动执行。
当对象消亡时,析构函数被自动执行。
这样就不用担心忘记对象的初始化和清除工作。
二.构造函数在C#中的运用构造函数的名字不能随便起,必须让编译器认得出才可以被自动执行。
它的命名方法既简单又合理:让构造函数与类同名。
除了名字外,构造函数的另一个特别之处是没有返回值类型,这与返回值类型为void的函数不同。
如果它有返回值类型,那么编译器将不知所措。
在你可以访问一个类的方法、属性或任何其它东西之前,第一条执行的语句是包含有相应类的构造函数。
甚至你自己不写一个构造函数,也会有一个缺省构造函数提供给你。
class TestClass{public TestClass(): base() {} // 由CLR提供}下面列举了几种类型的构造函数1)缺省构造函数class TestClass{public TestClass(): base() {}}上面已介绍,它由系统(CLR)提供。
c++ 构造函数复制构造函数C++构造函数和复制构造函数是面向对象编程中重要的概念。
构造函数是在创建对象时自动调用的函数,用于初始化对象的成员变量。
复制构造函数则是在对象复制时自动调用的函数,用于将一个对象的值复制到另一个对象中。
本文将介绍 C++ 构造函数和复制构造函数的概念、用法和注意事项。
1. 构造函数构造函数是一种特殊的成员函数,用于初始化对象的成员变量。
构造函数的名称必须与类名相同,没有返回值,也不需要显式调用。
当创建对象时,系统会自动调用该类的构造函数进行对象的初始化。
例如:```class MyClass {public:MyClass() {// 构造函数代码}};```在上面的示例中,定义了一个名为 MyClass 的类,该类包含一个构造函数。
当创建 MyClass 对象时,该构造函数将被自动调用进行对象的初始化。
在 C++ 中,构造函数可以有多个重载版本。
例如,可以定义一个带参数的构造函数:```class MyClass {public:MyClass(int value) {// 构造函数代码}};```在上面的示例中,定义了一个带一个整型参数的 MyClass 构造函数。
当使用 MyClass(int value) 创建对象时,该构造函数将被自动调用进行对象的初始化。
2. 复制构造函数复制构造函数是一种特殊的构造函数,用于将一个对象的值复制到另一个对象中。
当使用一个对象创建另一个对象时,系统会自动调用该类的复制构造函数进行对象的复制。
例如:```class MyClass {public:MyClass(const MyClass& other) {// 复制构造函数代码}};```在上面的示例中,定义了一个名为 MyClass 的类,该类包含一个复制构造函数。
当使用一个 MyClass 对象创建另一个 MyClass 对象时,该复制构造函数将被自动调用进行对象的复制。