第13章 类的构造、析构与赋值函数
含有指针变量的类需要重写拷贝构造函数,拷贝赋值函数,析构函数
含有指针变量的类需要重写拷贝构造函数,拷贝赋值函数,析构函数编译器⾃带拷贝构造(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++中构造函数,拷贝构造函数和赋值函数的区别和实现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++_构造函数与析构函数
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) 默认构造函数是构造对象时不提供参数的构造函数。
编写类string的构造函数、析构函数和赋值函数
编写类string的构造函数、析构函数和赋值函数在C++中,可以通过定义类来自定义一种数据类型。
类可以包含成员变量和成员函数,以模拟现实世界中的对象。
在许多应用程序中,字符串是一种常用的数据类型。
因此,我们可以通过编写一个类来实现一个自定义的字符串类型。
在这个类中,我们需要定义构造函数、析构函数和赋值函数。
构造函数用于初始化对象,析构函数用于在对象被销毁时释放资源,赋值函数用于将一个对象的值赋给另一个对象。
首先,我们来看构造函数。
构造函数可以有多种形式,例如默认构造函数、拷贝构造函数等。
在这个类中,我们可以定义一个接受字符串作为参数的构造函数,用于初始化对象。
例如:```class MyString {public:MyString(const char* str) {// 初始化对象}};```在上面的代码中,我们定义了一个名为MyString的类,其中包含一个接受const char*类型参数的构造函数。
在构造函数内部,我们可以使用strcpy函数将字符串复制到对象的成员变量中。
接下来是析构函数。
析构函数在对象被销毁时自动调用,用于释放资源。
例如,在我们的字符串类中,我们可以使用delete来释放字符串的内存:```class MyString {public:~MyString() {delete[] m_data;}};```上述代码中,我们定义了一个名为~MyString的析构函数,其中使用delete[]释放了m_data成员变量所指向的内存。
最后是赋值函数。
赋值函数用于将一个对象的值赋给另一个对象。
在字符串类中,我们可以使用strcpy将一个字符串的值赋给另一个对象。
例如:```class MyString {public:MyString& operator=(const MyString& rhs) {// 将rhs的值赋给对象return *this;}};```在上述代码中,我们定义了一个名为operator=的赋值函数,其返回类型为MyString&。
第13章 对象与类
1-20
【题目192】创建一个employee类,该类中有字符数组, 表示姓名、街道地址、市、省和邮政编码。把表示构造 函数、changname()、display()的函数的原型放在类定 义中,构造函数初始化每个成员,display()函数把完整 的对象数据打印出来。其中的数据成员是保护的,函数 是公共的。 【分析】该试题主要考查类的定义。其中在类中定义了保护 类型的数据成员,在类中声明了公共类型的函数,而将 函数的具体定义放在了类外。在类外定义函数时,需要 在前面加上类名::表示函数的归属。
1-22
【题目197】定义计数器类Counter。要求具有以下成员: 计数器值;可进行增值和减值记数;可提供记数值。
【题目198】编写一个程序,采用一个类求n!,并输出10!的 值。 【题目199】编写一个程序,设计一个Cdate类,它应该满 足下面的条件: (1)用这样的格式输出日期:日-月-年; (2)输出在当前日期上加两天后的日期; (3)设置日期。
1-13
习题
【题目185】对于对象和类的关系,说法不正确的是? A.同属于一类的对象,具有相同的数据成员和成员函数 B.对象是具体的,是类的对象,同其他变量一样,先定义 后使用 C.同一类的不同对象,其具有的操作可不同 D.不同类的对象,可有相同的操作 【分析】该试题主要考查对象和类的关系。对于如上4个选 项而言,源自于同一个类的对象必然具有相同的数据成 员和成员函数,而不同类的对象可以有相同操作,但同 一类的不同对象具有的操作也应是相同的。因此,选项C 是错误的。此外,对象是类的具体化,而类是对象的抽 象化,对象在使用前必须先定义或先创建。
•
•
•
1-5
类的声明
•
• • • • • • •
构造函数和析构函数总论
对于相同域中的对象:先构造的后析构,后构造的先 析构。
静态(static)类成员
一、静态数据成员 1、定义: class CTest { public ; static int count ; ┆ }; CTest rect1,rect2,… //定义多个对象 注: 无论生成多少个CTest对象,只有一个count,因此它是由 所有CTest对象共有的。静态数据成员只存储一处,供所有 对象共用。静态数据成员能够实现多个对象的数据共享。
构造函数和析构函数总论
在类中可以定义两个指定功能成员函数: 构造函数 析构函数 一、 构造函数 用来生成对象,可以初始化对象的数据成 员,构造函数在有对象生成时有系统自动调用。
class crectangle { private : int left ; int right ; public : crectangle( int L, int R) //构造函数 {left=L; right=R ;} void getcoord ( int *L , int *R ) {*L=left ; *R = right } };
const对象和const成员函数
①对象定义中加入const,表示该对象为常对象, 常对象中的数据成员为常变量,不能改变该类 中任何数据成员的值,数据成员必须有初值。 常对象用来保护对象中的数据不被修改; ②类中的函数定义中加入const,表示该函数为 常成员函数,只能引用本类中的数据成员,而 不能不能改变它们。常对象只允许调用常函数。 ③类中的数据成员定义中加入const,表示该数据 成员为常数据成员,其值是不能改变的,只能 通过构造函数的成员初始化表对其进行初始化。
二.析构函数
1 、析构函数:用来释放对象,在对象 删除前,用它来做一些清理工作,它在 类对象销毁时自动调用。
构造函数与析构函数
1
回想一下变量和函数参数的初始化 变量 定义与赋值结合起来: int number=9902; 函数 应用缺省参数: void add(int a=0, int b=0); 目的 便于编程、保证变量的值不会无意义,减小 程序出错的可能性。 构造函数和析构函数是类中的特殊的成员函数,构 造函数, 创建并初始化类的数据成员。析构函数 , 对象撤消时的清理工作,削除对象,释放内存。
14
// employee的类外定义 employee :: employee () : x (215) // 初始化表 { … } // show()的定义。 void employee :: show() { cout << "\n x的值是:"<< x << endl; } // 主函数 void main() { //生成对象并为x赋予初始值 employee obj; //调用show显示x的值 obj.show(); }
8
//Exanple:为类 Person增加构造函数 #include <string.h> class Person { private: char m_strName[20]; int m_nAge; int m_nSex; public: Person(const char *name,int age,char sex) { strcpy(m_strName,name); m_nAge=age; m_nSex=(sex=='m'?0:1); } void Register(char *Name,int Age,char Sex); void GetName(char *Name); int GetAge(); char GetSex();};
东软培训考核试题答案(内部资料)
东软培训考核试题答案(内部资料)⼀、单选题(共20分,每题1分)1、快速排序的时间复杂度_____。
A)B) O(n*n); C)O(n*n/2); ; D)O(log(n));2、计算程序执⾏完的结果:short a;char *p;a = 1234;p= (char *)&a*p = 56;请问题变量a的数值为______。
A)1234; B) 3456; C)5634;3、判断程序的结果:char * p = “Hello World”;*p = “A”;程序执⾏后的结果_______。
A) p指向的字符串为“Aello World”;“H ello World”;C)D) 结果未知;4、请问这个结构体所占的空间⼤⼩是______。
Typedef {Int a;Char b,Short c,Short d,}AA_t;A)16byte; B) 9 byte; D)85、有下列程序段char a[3],b[]=”China”;a = b;printf(“%s”,a);则______。
A)运⾏后将输出China Ch;C)运⾏后将输出Chi6、若有语句int * point,a =4 ;和point = &a______。
7 、语句int (*ptr)();的含义是______。
A)ptr是指向⼀维数组的指针变量;D)ptr是⼀个函数名,该函数的返回值是指向int类型的指针;8、若有以下定义和语句:struct student{int age;int num;};struct student stu[3] = {{1001,20},{1002,19},{1003,21}};main(){struct student *p;p = stu;...}则以下不正确的引⽤是______。
A)(p++)->num; B)p++; C)(*p).num;9、请正确指出下列指针的最确切的含义,int (*ptr)[3]、int *(*ptr)[4]、void* (*ptr)(void*)______。
构造函数和析构函数的作用
构造函数和析构函数的作用构造函数是一种特殊的成员函数,它没有返回类型,与类名相同,并且在创建对象时自动调用。
构造函数用于初始化对象的成员变量或执行一些必要的操作,确保对象的有效状态。
构造函数的主要作用如下:1.初始化成员变量构造函数用于初始化对象的成员变量。
可以通过构造函数对成员变量进行赋值操作,设置对象的初始状态。
在构造函数中可以使用this指针来访问对象的成员变量,通过this指针可以明确地指出当前对象。
2.为对象分配内存空间构造函数还负责为对象分配内存空间。
在创建对象时,构造函数会根据类的定义动态分配内存空间,保证对象的有效性,避免对象的成员变量冲突或访问越界等问题。
3.执行必要的操作构造函数还可以执行一些必要的操作,如连接数据库、初始化指针、打开文件等。
这些操作可以确保对象在创建时处于正确的状态,便于后续的使用。
4.支持函数重载构造函数支持函数重载,即在同一个类中可以定义多个构造函数,根据参数的不同进行区分。
这样可以方便地根据需要创建不同类型或不同初始状态的对象。
5.构造函数链在一些情况下,可以通过构造函数链来避免重复的代码。
构造函数链是指一个构造函数调用另一个构造函数来完成一部分初始化工作。
通过构造函数链,可以简化代码,并确保对象被正确初始化。
总之,构造函数的主要作用是为对象分配内存空间、初始化成员变量、执行必要的操作,确保对象的有效状态。
析构函数是与构造函数对应的一种特殊成员函数,用于清理对象内的资源并进行析构操作。
析构函数在对象销毁时自动调用,与构造函数相反。
析构函数的主要作用如下:1.释放动态分配的内存空间析构函数负责释放动态分配的内存空间,确保对象销毁时资源能够被正确释放。
如果在构造函数中动态分配了内存,应该在析构函数中释放,避免内存泄漏。
2.断开与外部资源的连接析构函数还可以断开与外部资源的连接,如关闭数据库连接、关闭文件等。
这样可以避免资源的浪费和异常。
3.执行必要的清理操作析构函数还可以执行一些必要的清理操作,如释放锁、关闭线程等。
高考数学 抽象函数赋值与构造-含解析
专题1-5 抽象函数赋值与构造一、抽象函数的赋值法赋值法是求解抽象函数问题最基本的方法,复制规律一般有以下几种: 1、……-2,-1,0,1,2……等特殊值代入求解; 2、通过的变换判定单调性;3、令式子中出现及判定抽象函数的奇偶性;4、换为确定周期性. 二、判断抽象函数单调性的方法:(1)凑:凑定义或凑已知,利用定义或已知条件得出结论;(2)赋值:给变量赋值要根据条件与结论的关系.有时可能要进行多次尝试. ①若给出的是“和型”抽象函数,判断符号时要变形为:或;()()12−f x f x ()f x ()−f x x +x T () =+y x f ()()()()111212)(x f x x x f x f x f −+−=−()()()()221212)(x x x f x f x f x f +−−=−②若给出的是“积型”抽象函数,判断符号时要变形为:或. 三、常见的抽象函数模型1、可看做的抽象表达式;2、可看做的抽象表达式(且);3、可看做的抽象表达式(且);4、可看做的抽象表达式.2022新高考2卷T8 1.已知函数()f x 的定义域为R ,且()()()(),(1)1f x y f x y f x f y f ++−==,则221()k f k ==∑( )A .3−B .2−C .0D .12023新高考1卷T112.(多选)已知函数()f x 的定义域为R ,()()()22f xy y f x x f y =+,则( ).A .()00f =B .()10f =C .()f x 是偶函数D .0x =为()f x 的极小值点2023·山东青岛·统考三模() =xy f ()()()112112x f x x x f x f x f −⎪⎪⎭⎫ ⎝⎛⋅=−()()()⎪⎪⎭⎫⎝⎛⋅−=−212212x x x f x f x f x f ()()()+=+f x y f x f y ()=f x kx ()()()+=f x y f x f y ()=xf x a 0>a 1≠a ()()()=+f xy f x f y ()log =a f x x 0>a 1≠a ()()()=f xy f x f y ()=af x x 重点题型·归类精讲1.设()f x 为定义在整数集上的函数,()11f =,()20f =,()10f −<,对任意的整数,x y 均有()()()()()11f x y f x f y f x f y +=−+−.则()55f =______.2023·山东滨州·三模2.(多选)已知连续函数()f x 对任意实数x 恒有()()()f x y f x f y +=+,当0x >时,()0f x <,(1)2f =-,则以下说法中正确的是( ) A .f (0)=0B .f (x )是R 上的奇函数C .f (x )在[-3,3]上的最大值是6D .不等式()232()(3)4f x f x f x −<+的解集为213xx ⎧⎫<<⎨⎬⎩⎭安徽省皖江名校联盟2024届高三上学期10月第二次联考3.已知函数不是常数函数,且满足以下条件:①,其中;②,则( )A .0B .1C .2D .4.(多选)已知定义在R 上的函数()f x 满足()()()()()()()()2,02,01f xy f x f y f x f y f f f =−−+<≠,且()0f x >,则( ) A .()01f =B .()12f −=C .()()2f x f x −=D .()()f x f x −=5.已知函数及其导函数的定义域均为,对任意的,恒有,则下列说法正确的个数是( )①;②必为奇函数;③;④若,则.A .1B .2C .3D .42023·浙江嘉兴·统考模拟6.已知函数的定义域为,且,,则的值是( )A .9B .10C .11D .12(),y f x x =∈R ()()()()f a b f a b f a f b ++−=,a b ∈R ()10f =()2026f −=2−()f x ()f x 'R ,R x y ∈()()()()2f x y f x y f x f y ++−=()00f =()f x '()()00f x f +≥1(1)2f =202311()2n f n ==∑()f x R ()()()()31,00,f x x f x x ⎛⎫=∈−∞+∞ ⎪⎝⎭()()()2f x f y xy f x y ++=+()3f2023届江苏连云港校考7.已知函数,任意,满足,且,则的值为( )A .B .0C .2D .48.已知,都是定义在上的函数,对任意x ,y 满足,且,则下列说法正确的是( )A .B .函数的图象关于点对称C .D .若,则2023绍兴·高二期末9.已知函数的定义域为R ,且,为奇函数,,则( ) A . B . C .0 D .10.(多选)已知函数()f x 的定义域为R ,()()()f x y f x f y +=+,则( )A .()00f =B .()f x 是奇函数 C .0x =为()f x 的极小值点D .若()11f =,则()20232023f =11.(多选)设()f x 是定义在R 上的函数,对,x y ∀∈R ,有()()()()22f x y f x y f x f y +−−=++,且()00f ≠,则( )A .()()0f x f x −−=B .()()40f x f x +−=C .()()()()02420242f f f f ++++=−()f x x y R ∈,()()()()22f x y f x y f x f y +−=−()()1220f f ==,()()()1290f f f +++2−()f x ()g x R ()()()()()f x y f x g y g x f y −=−()()210f f −=≠()01f =()21g x +()1,0()()110g g +−=()11f =()202311n f n ==∑()f x ()()()28f x f x f ++=()21f x +1122f ⎛⎫= ⎪⎝⎭22112k kf k =⎛⎫−= ⎪⎝⎭∑11−12−212。
C#类的构造函数与析构函数
C#类的构造函数与析构函数1.构造函数:类的构造函数是用来创建类的一个实例。
创建一个实例的一般形式:类名实例名= new 类名(构造函数参数列表);构造函数和类中其他函数相比,是较为特殊的,它的名称必须和类同名。
定义一个构造函数的一般形式是:Class 类名{类名(参数表);//就是定义构造函数{//语句}}例子:using System;class MyClass{MyClass(){Console.WriteLine("启动构造函数");Console.ReadLine();}public static void Main(){MyClass cM = new MyClass();}}运行结果:MyClass()就是一个构造函数,构造函数是没有任何返回值的。
构造函数也可以携带参数,看下面的例子:using System;class userName{string Uname;//定义一个带参数的构造函数public userName(string name){Console.WriteLine("新建一个用户:");Uname = name;}public void ShowName(){Console.WriteLine("用户名是:"+ Uname); }public static void Main(){//用带参数的构造函数创建类的一个实例userName uN1 = new userName("zhanghua"); uN1.ShowName();Console.ReadLine();}}运行结果:2.析构函数定义一个析构函数的一般形式是:Class 类名{~类名(参数表);//定义析构函数{//语句}}析构函数的使用:using System;class First{public First(){Console.WriteLine("First's constructor is called");}~First(){Console.WriteLine("First's destructor is called");}}class Second{public Second(){Console.WriteLine("Sencond's constructor is called");}~Second(){Console.WriteLine("Second's destructor is called");}}class Third{public Third(){Console.WriteLine("Third's constructor is called");}~Third(){Console.WriteLine("Third's destructor is called");}}public class MainClass{public static void Main(){First myObject1 = new First();Second myObject2 = new Second();Third myObject3 = new Third();}}运行结果:。
[学习C++]构造函数 析构函数和赋值操作符
几乎所有的类都有一个或多个构造函数,一个析构函数和一个赋值操作符。
这没什么奇怪的,因为它们提供的都是一些最基本的功能。
构造函数控制对象生成时的基本操作,并保证对象被初始化;析构函数摧毁一个对象并保证它被彻底清除;赋值操作符则给对象一个新的值。
在这些函数上出错就会给整个类带来无尽的负面影响,所以一定要保证其正确性。
本章我将指导如何用这些函数来搭建一个结构良好的类的主干。
构造函数,析构函数和赋值操作符几乎所有的类都有一个或多个构造函数,一个析构函数和一个赋值操作符。
这没什么奇怪的,因为它们提供的都是一些最基本的功能。
构造函数控制对象生成时的基本操作,并保证对象被初始化;析构函数摧毁一个对象并保证它被彻底清除;赋值操作符则给对象一个新的值。
在这些函数上出错就会给整个类带来无尽的负面影响,所以一定要保证其正确性。
本章我将指导如何用这些函数来搭建一个结构良好的类的主干。
条款11: 为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符看下面一个表示string对象的类:// 一个很简单的string类class string {public:string(const char *value);~string();... // 没有拷贝构造函数和operator=private:char *data;};string::string(const char *value){if (value) {data = new char[strlen(value) + 1];strcpy(data, value);}else {data = new char[1];*data = '\0';}}inline string::~string() { delete [] data; }请注意这个类里没有声明赋值操作符和拷贝构造函数。
这会带来一些不良后果。
如果这样定义两个对象:string a("hello");string b("world");其结果就会如下所示:a: data——> "hello\0"b: data——> "world\0"对象a的内部是一个指向包含字符串"hello"的内存的指针,对象b的内部是一个指向包含字符串"world"的内存的指针。
类、构造函数、析构函数
类:1、在类体中不允许对所定义的数据成员进行初始化。
2、类的成员函数描述类所表达的问题的行为。
类中所有的成员函数都必须在类体内进行说明。
但成员函数的定义既可以在类体内给出,也可以在类体外给出。
第一种方式是将成员函数直接定义在类的内部。
第二种方式是在类声明中给出对成员函数的说明,而在类外部对成员函数进行定义(但成员函数仍然在类范围内)。
这种在类外部定义的成员函数的一般格式是:<返回类型><类名>::<成员函数名>(<参数表>){<函数体>}在类体外定义成员函数时,要注意必须在成员函数名前加上类名和作用域运算符(::)。
作用域运算符用来标识某个成员属于某个类。
作用域运算符的使用格式如下:<类名>::<成员函数名>(<参数表>)或<类名>::<数据成员名>成员函数的两种定义方式之间是有差别的。
如果一个成员函数的声明和定义都在类体内,那么这个成员函数就是内联函数。
如果一个成员函数的声明在类体内,而定义在类体外,这时对该成员函数的调用是按一般函数进行的。
如果要将定义在类体外的成员函数也作为内联函数处理,就必须在成员函数的定义前加上关键字“inline”,以此显式地说明该成员函数也是一个内联函数。
成员函数除了可以定义为内联函数以外,也可以进行重载,可以对其参数设置默认值。
6.3 构造函数和析构函数1、构造函数和析构函数的定义。
构造函数的作用是在对象被创建时利用特定的值构造对象,将对象初始化为一种特定的状态,使该对象具有区别于其他对象的特征。
构造函数在对象被创建的时候由系统自动调用。
构造函数也是类的成员函数,但它是一种特殊的成员函数,它除了具有一般成员函数的特性之外,还具有一些特殊的性质:(1)构造函数的名字必须与类名相同;(2)构造函数不指定返回类型,它隐含有返回值,由系统内部使用;(3)构造函数可以有一个或多个参数,因此构造函数可以重载;(4)在创建对象时,系统会自动调用构造函数。
2、缺省构造函数和缺省析构函数缺省构造函数就是调用时不必提供参数的构造函数。
构造函数和析构函数和复制构造函数
实验五【实验内容】构造函数和析构函数和复制构造函数构造函数1. 构造函数是类的一个特殊成员函数,它的函数名与类名相同。
2. 构造函数定义了对象数据成员的初始化方法,它只在创建对象时被系统自动调用,并且只在创建对象时调用一次,是为创建的对象分配内存空间和对数据成员进行初始化。
3. 构造函数无函数类型,没有返回值,一般都声明为公有函数。
4.C++规定,每个类必须有构造函数,没有构造函数就不能创建对象。
5.如果程序中未声明构造函数,则系统自动产生出一个默认形式的构造函数,如果提供了一个构造函数,系统就不能自动提供一个默认的构造函数。
6.构造函数可以重载,即可以定义多个参数及参数类型不同的构造函数。
复制构造函数又称拷贝构造函数,是一种特殊的构造函数,其形参为本类的对象引用。
功能是把初始值对象的每个数据成员的值都复制到新建立的对象。
如果程序员没有为类声明拷贝初始化构造函数,则编译器自己生成一个拷贝构造函数。
1. 当用类的一个对象去初始化该类的另一个对象时系统自动调用它实现拷贝赋值。
2. 若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数。
3. 当函数的返回值是类对象时,系统自动调用拷贝构造函数。
析构函数析构函数也是特殊的类成员函数,它没有返回类型,没有参数,不能随意调用,也没有重载,只有在类的生命周期结束的时候,由系统自动调用。
析构函数和构造函数的最主要的区别:调用期不同、构造函数可以有参数可以重载。
实验1设计一个学生类stu,其中含有数据成员name、english和math,分别表示学生的姓名、英语成绩与数学成绩,使用类的成员函数output 和total输出学生的基本信息和总成绩,并完成在main函数中的相应调用。
#include <iostream>using namespace std;class stu{public:stu(char n[]="",double e=0.0,double m=0.0);~stu();void input();void output();void total();private:char name[8];double english,math;};stu::stu(char n[],double e,double m){strcpy(name,n);english=e;math=m;}stu::~stu(){}void stu::input(){cout<<"请输入学生的姓名、英语成绩与数学成绩:"<<endl;cin>>name>>english>>math;}void stu::output (){cout<<"学生的姓名、英语成绩与数学成绩:"<<name<<","<<english<<","<<math<<endl;}void stu::total (){cout<<"学生的总成绩是:"<<english+math<<endl;}void main(){stu s1("张思宁",95,80),s2;s2.input ();s1.output ();s1.total ();s2.output() ;s2.total ();}实验2练习书上112页例4-2,熟悉复制构造函数被调用的3种情况。
C++编程小贴士
问题1:类的构造函数、析构函数与赋值函数构造函数、析构函数与赋值函数是每个类最基本的函数。
它们太普通以致让人容易麻痹大意,其实这些貌似简单的函数就象没有顶盖的下水道那样危险。
每个类只有一个析构函数和一个赋值函数,但可以有多个构造函数(包含一个拷贝构造函数,其它的称为普通构造函数)。
对于任意一个类A,如果不想编写上述函数,C++编译器将自动为A 产生四个缺省的函数,如A(void); // 缺省的无参数构造函数A(const A &a); // 缺省的拷贝构造函数~A(void); // 缺省的析构函数A & operate =(const A &a); // 缺省的赋值函数这不禁让人疑惑,既然能自动生成函数,为什么还要程序员编写?原因如下:(1)如果使用“缺省的无参数构造函数”和“缺省的析构函数”,等于放弃了自主“初始化”和“清除”的机会,C++发明人Stroustrup 的好心好意白费了。
(2)“缺省的拷贝构造函数”和“缺省的赋值函数”均采用“位拷贝”而非“值拷贝”的方式来实现,倘若类中含有指针变量,这两个函数注定将出错。
对于那些没有吃够苦头的C++程序员,如果他说编写构造函数、析构函数与赋值函数很容易,可以不用动脑筋,表明他的认识还比较肤浅,水平有待于提高。
本章以类String 的设计与实现为例,深入阐述被很多教科书忽视了的道理。
String的结构如下:class String{public:String(const char *str = NULL); // 普通构造函数String(const String &other); // 拷贝构造函数~ String(void); // 析构函数String & operate =(const String &other); // 赋值函数private:char *m_data; // 用于保存字符串};作为比 C 更先进的语言,C++提供了更好的机制来增强程序的安全性。
C++复习5大基础函数(析构函数、构造函数、内联函数、拷贝构造函数、友元函数)详解
1、析构函数2、构造函数3、内联函数4、拷贝构造函数5、友元函数1、析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。
析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
2、构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回void。
构造函数可用于为某些成员变量设置初始值。
3、内联函数有时称作在线函数(inline)。
函数的调用是需要付出一定的时空开销的,因为系统在调用函数时,要保留现场,然后转入被调用函数去执行,调用完,再返回主调函数,此时再恢复现场,这些操作。
所谓“内联函数”就是将很简单的函数“内嵌”到调用他的程序代码中,只样做的目的是为了节约下原本函数调用时的时空开销。
但必须注意的是:作为内联函数,函数体必须十分简单,不能含有循环、条件、选择等复杂的结构,否则就不能做为内联函数了。
事实上,即便你没有指定函数为内联函数,有的编译系统也会自动将很简单的函数作为内联函数处理;而对于复杂的函数,即便你指定他为内联函数,系统也不会理会的。
内联函数也有一定的局限性。
就是函数中的执行代码不能太多了,如果,内联函数的函数体过大,一般的编译器会放弃内联方式,而采用普通的方式调用函数。
这样,内联函数就和普通函数执行效率一样了。
4、拷贝构造函数拷贝构造函数,又称复制构造函数。
复制构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量。
它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象.为什么需要拷贝构造函数?把参数传递给函数有三种方法,一种是传值,一种是传地址,一种是传引用。
传值与其他两种方式不同的地方在于当使用传值方式的时候,会在函数里面生成传递参数的一个副本,这个副本的内容是按位从原始参数那里复制过来的,两者的内容是相同的。
派生类的构造函数赋值和析构函数执行顺序
派生类的构造函数赋值和析构函数执行顺序基类的构造函数和析构函数是不能被继承的1、如果基类没有定义构造函数,派生类也可以不定义构造函数,使用默认的构造函数,其新增成员的初始化可以用其他公有函数来实现.2.如果基类中定义了缺省构造函数或根本没有定义任何一个构造函数(此时,由编译器自动生成缺省构造函数)时,在派生类构造函数的定义中可以省略对基类构造函数的调用,即省略<基类名>(<参数表>)。
3、如果基类定义了带有形参表的构造函数派生类就必须加入新的构造函数,提供一个将参数传递给基类构造函数的途径,保证在基类进行初始化时能够获得必要的数据因此,如果基类的构造函数定义了一个或多个参数时,派生类必须定义构造函数。
4.对派生类对象的清理工作也需要加入新的析构函数。
5. 子对象的情况与基类相同。
派生类的数据成员由所有基类的数据成员与派生类新增的数据成员共同组成,如果派生类新增成员中包括其他类的对象(子对象),派生类的数据成员中实际上还间接包括了这些对象的数据成员。
因此,构造派生类的对象时,必须对基类数据成员、新增数据成员和成员对象的数据成员进行初始化。
派生类的构造函数必须要以合适的初值作为参数,隐含调用基类和新增对象成员的构造函数,来初始化它们各自的数据成员,然后再加入新的语句对新增普通数据成员进行初始化。
派生类构造函数的一般格式如下:<派生类名>::<派生类名>(<参数表>) : <基类名1>(<参数表1>),……,<基类名n>(<参数表n>),<子对象名1>(<参数表n+1>),……,<子对象名m>(<参数表n+m>){派生类新增成员的初始化函数语句;}说明:(1) 对基类成员和子对象成员的初始化必须在成员初始化列表中进行,新增成员的初始化既可以在成员初始化列表中进行,也可以在构造函数体中进行。
类模板 中的构造与析构
类模板中的构造与析构
在C++中,类模板是一种通用的类定义,可以用来创建特定类型的类。
类模板中的构造函数和析构函数与普通类的构造函数和析构函数有一些不同之处。
首先,类模板中的构造函数和析构函数的定义方式与普通类有所不同。
在类模板中,构造函数和析构函数的定义需要在类模板外部进行,通常是在类模板定义后面单独定义。
定义构造函数和析构函数时需要在函数名前加上类模板的参数列表,以告诉编译器这是类模板的特定实例的构造函数或析构函数。
其次,类模板中的构造函数和析构函数可以使用模板参数来定义。
这意味着可以在构造函数和析构函数中使用类模板的参数,以便在实例化类模板时将特定的类型传递给构造函数和析构函数。
另外,类模板中的构造函数和析构函数可以有不同的实现,具体取决于类模板的参数类型。
这使得类模板可以根据不同的参数类型来执行不同的初始化和清理操作。
需要注意的是,类模板中的构造函数和析构函数的定义和使用
需要遵循类模板的语法规则,并且需要考虑到模板参数类型的特殊性。
此外,对于类模板中的构造函数和析构函数,也需要考虑到模板参数类型的特殊性,以确保在实例化类模板时能够正确地调用构造函数和析构函数。
总之,类模板中的构造函数和析构函数与普通类有所不同,需要特别注意类模板的语法规则和模板参数类型的特殊性,以确保能够正确地定义和使用构造函数和析构函数。
python 类析构函数
python 类析构函数Python是一种高级编程语言,支持多种编程范式,包括面向对象编程思想。
在Python中,类是一种用户自定义的数据类型,它封装了数据和行为,并提供了访问和操作这些数据的接口。
类的构造函数和析构函数是两个十分重要的概念,其中析构函数扮演着释放资源的角色。
本文将详细介绍Python中的类析构函数。
1、类的构造函数和析构函数在Python中,类的构造函数是指在创建类的实例时自动被调用的函数。
构造函数的作用是初始化实例变量。
在Python中,构造函数为__init__(self),它的第一个参数self指向类的实例对象本身。
而析构函数则是当类的实例对象被销毁时自动调用的函数。
析构函数的作用是释放实例占用的资源。
在Python 中,析构函数为__del__(self)。
2、析构函数的使用在Python中,类的析构函数可以用来释放一些资源,比如关闭文件、关闭数据库连接、释放内存等。
当类的实例对象被销毁时,Python会自动调用它的析构函数。
我们可以通过实现类的析构函数来释放一些资源,从而避免资源泄漏。
下面是一个简单的例子,展示了如何在Python中使用析构函数:class MyClass: def __init__(self): print("构造函数被调用")def __del__(self): print("析构函数被调用")obj = MyClass() del obj 输出结果为:构造函数被调用析构函数被调用在上面的例子中,我们创建了一个名为MyClass的类,并实现了它的构造函数和析构函数。
当我们创建了一个名为obj的MyClass类的实例对象时,构造函数被调用并输出“构造函数被调用”的信息。
当我们调用del语句删除实例对象时,Python会自动调用析构函数并输出“析构函数被调用”的信息。
3、注意事项在Python中,析构函数不是被立即调用的。
类的析构函数
类的析构函数类的析构函数(Destructor)是类中的一种特殊成员函数,它在对象的生命周期结束时自动调用。
它的作用是释放类对象占用的内存空间、关闭相关资源和清除对象状态等。
因此,正确实现类的析构函数是保障程序数据完整性和稳定性的重要措施之一。
一、析构函数的命名和定义在C++中,类的析构函数的函数名必须与类名相同,只不过在函数名前面加上一个“~”(一个波浪号)。
例如,如果一个类名为“Test”,则析构函数的函数名应该是“~Test()”。
析构函数的定义在类的声明的下方,与构造函数类似,只不过在函数名前面加上一个“~”。
以下是一个简单的类的定义及其构造函数和析构函数的示例:``` class MyClass { public: MyClass(); // 构造函数 ~MyClass(); // 析构函数private: int *ptr; }; MyClass::MyClass(){ ptr = new int; } MyClass::~MyClass(){ delete ptr; } ```二、析构函数的特性1、在对象销毁时自动调用:析构函数在对象销毁时自动调用,不需要手动调用。
2、没有返回值和参数:析构函数没有返回类型和参数列表,因为它只是一个函数名和类名相同的函数。
3、只有一个析构函数:C++中只有一个析构函数,如果用户没有定义,默认的析构函数会执行对象的析构操作。
4、父类的析构函数:如果一个类继承了其他类,它的父类的析构函数也会被执行,这个过程被称为析构函数的“递归调用”。
5、虚析构函数:在当我们希望子类的析构函数能够释放掉子类中已经被分配的空间时,需要定义虚析构函数,这样在销毁时就可以调用子类的析构函数。
三、析构函数的常见问题和注意点1、构造函数与析构函数的区别:构造函数在对象创建时被自动调用,而析构函数则是在对象销毁时被自动调用。
构造函数的目的是初始化对象的成员数据,而析构函数的目的是清除对象的状态或占用资源。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第十三章类的构造、析构与赋值函数构造函数、析构函数与赋值函数是每个类最基本的函数。
它们太普通以致让人容易麻痹大意,其实这些貌似简单的函数就象没有顶盖的下水道那样危险。
每个类只有一个析构函数和一个赋值函数,但可以有多个构造函数(包含一个拷贝构造函数,其它的称为普通构造函数)。
对于任意一个类A,如果不想编写上述函数,C++编译器将自动为A产生四个缺省的函数,如A(void); // 缺省的无参数构造函数A(const A &a); // 缺省的拷贝构造函数~A(void); // 缺省的析构函数A & operate =(const A &a); // 缺省的赋值函数这不禁让人疑惑,既然能自动生成函数,为什么还要程序员编写?原因如下:(1)如果使用“缺省的无参数构造函数”和“缺省的析构函数”,等于放弃了自主“初始化”和“清除”的机会,C++发明人Stroustrup的好心好意白费了。
(2)“缺省的拷贝构造函数”和“缺省的赋值函数”均采用“位拷贝”而非“值拷贝”的方式来实现,倘若类中含有指针变量,这两个函数注定将出错。
对于那些没有吃够苦头的C++程序员,如果他说编写构造函数、析构函数与赋值函数很容易,可以不用动脑筋,表明他的认识还比较肤浅,水平有待于提高。
本章以类String的设计与实现为例,深入阐述被很多教科书忽视了的道理。
String 的结构如下:class String{public:String(const char *str = NULL); // 普通构造函数String(const String &other); // 拷贝构造函数~ String(void); // 析构函数String & operate =(const String &other); // 赋值函数private:char *m_data; // 用于保存字符串};13.1 构造函数与析构函数的起源作为比C更先进的语言,C++提供了更好的机制来增强程序的安全性。
C++编译器具有严格的类型安全检查功能,它几乎能找出程序中所有的语法问题,这的确帮了程序员的大忙。
但是程序通过了编译检查并不表示错误已经不存在了,在“错误”的大家庭里,“语法错误”的地位只能算是小弟弟。
级别高的错误通常隐藏得很深,就象狡猾的罪犯,想逮住他可不容易。
根据经验,不少难以察觉的程序错误是由于变量没有被正确初始化或清除造成的,而初始化和清除工作很容易被人遗忘。
Stroustrup在设计C++语言时充分考虑了这个问题并很好地予以解决:把对象的初始化工作放在构造函数中,把清除工作放在析构函数中。
当对象被创建时,构造函数被自动执行。
当对象消亡时,析构函数被自动执行。
这下就不用担心忘了对象的初始化和清除工作。
构造函数与析构函数的名字不能随便起,必须让编译器认得出才可以被自动执行。
Stroustrup的命名方法既简单又合理:让构造函数、析构函数与类同名,由于析构函数的目的与构造函数的相反,就加前缀‘~’以示区别。
除了名字外,构造函数与析构函数的另一个特别之处是没有返回值类型,这与返回值类型为void的函数不同。
构造函数与析构函数的使命非常明确,就象出生与死亡,光溜溜地来光溜溜地去。
如果它们有返回值类型,那么编译器将不知所措。
为了防止节外生枝,干脆规定没有返回值类型。
(以上典故参考了文献[Eekel, p55-p56])12.2 构造函数的初始化表构造函数有个特殊的初始化方式叫“初始化表达式表”(简称初始化表)。
初始化表位于函数参数表之后,却在函数体{} 之前。
这说明该表里的初始化工作发生在函数体内的任何代码被执行之前。
构造函数初始化表的使用规则:如果类存在继承关系,派生类必须在其初始化表里调用基类的构造函数。
例如class A{…A(int x); // A的构造函数};class B : public A{…B(int x, int y);// B的构造函数};B::B(int x, int y): A(x) // 在初始化表里调用A的构造函数{…}◆类的const常量只能在初始化表里被初始化,因为它不能在函数体内用赋值的方式来初始化(参见12.4节)。
◆类的数据成员的初始化可以采用初始化表或函数体内赋值两种方式,这两种方式的效率不完全相同。
非内部数据类型的成员对象应当采用第一种方式初始化,以获取更高的效率。
例如class A{…A(void); // 无参数构造函数A(const A &other); // 拷贝构造函数A & operate =( const A &other); // 赋值函数};class B{public:B(const A &a); // B的构造函数private:A m_a; // 成员对象};示例13-2(a)中,类B的构造函数在其初始化表里调用了类A的拷贝构造函数,从而将成员对象m_a初始化。
示例13-2 (b)中,类B的构造函数在函数体内用赋值的方式将成员对象m_a初始化。
我们看到的只是一条赋值语句,但实际上B的构造函数干了两件事:先暗地里创建m_a 对象(调用了A的无参数构造函数),再调用类A的赋值函数,将参数a赋给m_a。
示例13-2(a) 成员对象在初始化表中被初始化示例13-2(b) 成员对象在函数体内被初始化对于内部数据类型的数据成员而言,两种初始化方式的效率几乎没有区别,但后者的程序版式似乎更清晰些。
若类F的声明如下:class F{public:F(int x, int y); // 构造函数private:int m_x, m_y;int m_i, m_j;}示例13-2(c)中F的构造函数采用了第一种初始化方式,示例13-2(d)中F的构造函数采用了第二种初始化方式。
示例13-2(c) 数据成员在初始化表中被初始化示例13-2(d) 数据成员在函数体内被初始化13.3 构造和析构的次序构造从类层次的最根处开始,在每一层中,首先调用基类的构造函数,然后调用成员对象的构造函数。
析构则严格按照与构造相反的次序执行,该次序是唯一的,否则编译器将无法自动执行析构过程。
一个有趣的现象是,成员对象初始化的次序完全不受它们在初始化表中次序的影响,只由成员对象在类中声明的次序决定。
这是因为类的声明是唯一的,而类的构造函数可以有多个,因此会有多个不同次序的初始化表。
如果成员对象按照初始化表的次序进行构造,这将导致析构函数无法得到唯一的逆序。
[Eckel, p260-261]13.4 示例:类String的构造函数与析构函数// String的普通构造函数String::String(const char *str){if(str==NULL){m_data = new char[1];*m_data = ‘\0’;}else{int length = strlen(str);m_data = new char[length+1];strcpy(m_data, str);}}// String的析构函数String::~String(void){delete [] m_data;// 由于m_data是内部数据类型,也可以写成 delete m_data;}13.5 不要轻视拷贝构造函数与赋值函数由于并非所有的对象都会使用拷贝构造函数和赋值函数,程序员可能对这两个函数有些轻视。
请先记住以下的警告,在阅读正文时就会多心:本章开头讲过,如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。
倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。
以类String的两个对象a,b为例,假设a.m_data的内容为“hello”,b.m_data的内容为“world”。
现将a赋给b,缺省赋值函数的“位拷贝”意味着执行b.m_data = a.m_data。
这将造成三个错误:一是 b.m_data原有的内存没被释放,造成内存泄露;二是b.m_data和a.m_data指向同一块内存,a或b任何一方变动都会影响另一方;三是在对象被析构时,m_data被释放了两次。
拷贝构造函数和赋值函数非常容易混淆,常导致错写、错用。
拷贝构造函数是在对象被创建时调用的,而赋值函数只能被已经存在了的对象调用。
以下程序中,第三个语句和第四个语句很相似,你分得清楚哪个调用了拷贝构造函数,哪个调用了赋值函数吗?String a(“hello”);String b(“world”);String c = a; // 调用了拷贝构造函数,最好写成 c(a);c = b; // 调用了赋值函数本例中第三个语句的风格较差,宜改写成String c(a) 以区别于第四个语句。
13.6 示例:类String的拷贝构造函数与赋值函数// 拷贝构造函数String::String(const String &other){// 允许操作other的私有成员m_dataint length = strlen(other.m_data);m_data = new char[length+1];strcpy(m_data, other.m_data);}// 赋值函数String & String::operate =(const String &other){// (1) 检查自赋值if(this == &other)return *this;// (2) 释放原有的内存资源delete [] m_data;// (3)分配新的内存资源,并复制内容int length = strlen(other.m_data);m_data = new char[length+1];strcpy(m_data, other.m_data);// (4)返回本对象的引用return *this;}类String拷贝构造函数与普通构造函数(参见13.4节)的区别是:在函数入口处无需与NULL进行比较,这是因为“引用”不可能是NULL,而“指针”可以为NULL。
类String的赋值函数比构造函数复杂得多,分四步实现:(1)第一步,检查自赋值。
你可能会认为多此一举,难道有人会愚蠢到写出 a = a 这样的自赋值语句!的确不会。
但是间接的自赋值仍有可能出现,例如也许有人会说:“即使出现自赋值,我也可以不理睬,大不了化点时间让对象复制自己而已,反正不会出错!”他真的说错了。
看看第二步的delete,自杀后还能复制自己吗?所以,如果发现自赋值,应该马上终止函数。
注意不要将检查自赋值的if语句if(this == &other)错写成为if( *this == other)(2)第二步,用delete释放原有的内存资源。