C++中复制构造函数与赋值运算符函数研究
- 格式:pdf
- 大小:345.94 KB
- 文档页数:3
详解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.拷贝构造函数的形式对于类X,如果它的函数形式如下a) X&b) const X&c) volatile X&d) const volatile X&且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数X::X(const X&);是拷贝构造函数X::X(const X&,int val = 10);是拷贝构造函数2.⼀个类中可以存在超过⼀个拷贝构造函数class X {public:X(const X&);X(X&); // OK};编译器根据实际情况调⽤const拷贝构造函数或⾮const的拷贝构造函数3.默认的拷贝构造函数⾏为a)先调⽤⽗类的拷贝构造函数b)如果数据成员为⼀个类的实例,则调⽤该类的拷贝构造函数c)其他成员按位拷贝4.默认的赋值构造函数⾏为a)先调⽤⽗类的赋值构造函数b)如果数据成员为⼀个类的实例,则调⽤该类的赋值构造函数c)其他成员按位拷贝5.提供显⽰的拷贝和赋值构造函数基本的原则是⼦类⼀定要调⽤⽗类的相应函数,参考⽅式Derive(const Derive& obj):Base(obj){…...}Derive& operator =(const Derive &obj){if ( this == &obj )return *this;//⽅式⼀Base::operator =(obj);//⽅式⼆static_cast<Base&>(*this) = obj;return *this;}另外当你的成员变量有const或者引⽤,系统⽆法为你提供默认的拷贝和赋值构造函数,我们必须⾃⼰处理这些特殊的情况。
拷贝构造函数和赋值运算符的认识1. 拷贝构造函数⽣成新的类对象,⽽赋值运算符是给已有的对象重新赋值。
2. 由于拷贝构造函数是直接构造⼀个新的类对象,所以在初始化这个对象之前不⽤检验源对象是否和新对象相同。
⽽赋值运算符则需要这个操作,另外赋值运算中如果原来的对象中已有内存分配要先把内存释放掉。
3. *注意:当类中有指针类型的成员变量时,⼀定要重写拷贝构造函数和赋值运算发,不要使⽤默认的。
//copy constructor 声明string(const string&);//assign operator 声明string& operator=(const string& rhs);//拷贝构造函数的实现string::string(const string& another) {std::cout << "拷贝构造函数被调⽤:\n";m_data = new char[strlen(another.m_data) + 1];strcpy(m_data, another.m_data);}// 赋值运算string& string::operator=(const string& rhs) {std::cout << "赋值运算符被调⽤:\n";if (this == &rhs) return *this;delete[]m_data;m_data = new char[strlen(rhs.m_data) + 1];strcpy(m_data, rhs.m_data);return *this;}深拷贝、浅拷贝说到拷贝构造函数,就不得不提深拷贝和浅拷贝。
通常,默认⽣成的拷贝构造函数和赋值运算符,只是简单的进⾏值的复制。
例如:上⾯的Person类,字段只有int和string两种类型,这在拷贝或者赋值时进⾏值复制创建的出来的对象和源对象也是没有任何关联,对源对象的任何操作都不会影响到拷贝出来的对象。
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++中,可以使用拷贝构造函数或赋值运算符重载来拷贝数组。
拷贝构造函数可以创建一个新的对象,并将其初始化为另一个对象的副本。
可以定义一个接受单个参数的构造函数,该参数是一个指向要拷贝的数组的指针,然后使用指针操作将数组的内容复制到新对象中。
例如:class MyArray {private:int* arr;int size;public:// 拷贝构造函数MyArray(const MyArray& other) {size = other.size;arr = new int[size];for (int i = 0; i < size; i++) {arr[i] = other.arr[i];}}// 赋值运算符重载MyArray& operator=(const MyArray& other) {if (this != &other) {delete[] arr;size = other.size;arr = new int[size];for (int i = 0; i < size; i++) {arr[i] = other.arr[i];}}return *this;}// 其他成员函数...};在上面的示例中,MyArray类包含一个私有的整型指针数组和一个私有的数组大小。
拷贝构造函数和赋值运算符重载都接受一个指向要拷贝的数组的指针,并使用指针操作将数组内容复制到新对象中。
在赋值运算符重载中,还需要检查自赋值情况(即this != &other),并在必要时释放原有内存并重新分配内存空间。
赋值构造函数和赋值运算符⼀、复制构造函数1、简介复制构造函数⽤于将⼀个对象复制到新创建的对象中。
它⽤于初始化过程中(包括调⽤函数时按值传递参数),⽽不是常规的赋值过程中。
其原型通常如下:Class_name(const Class_name &);它接受⼀个指向类对象的常量引⽤作为参数。
例如,String类的赋值构造函数的原型如下:String(const String &);2、何时调⽤新建⼀个对象并初始化为同类现有对象时,复制构造函数将被调⽤。
假设st是⼀个已有的Stirng对象(假设的,不是平常⽤的那个string),则下⾯四种声明都将调⽤复制构造函数:①String st1(st);②String st1=st;③String st1=String(st)④String *pst=new String(st);上述②、③这两种声明可能会使⽤复制构造函数直接创建st1,也可能使⽤复制构造函数⽣成⼀个临时对象,然后将临时对象的内容赋给st1,取决于具体实现。
像④,它会使⽤st初始化⼀个匿名对象,并将新对象的地址赋给pst指针。
3、默认复制构造函数的功能默认的复制构造函数逐个复制⾮静态成员(浅拷贝),复制的是成员的值。
假设String类型有成员str(const char *),len(int),那么下述语句:String st1=st;与下⾯的代码等效:String st1;st1.str=st.str;st1.len=st.len;⼆、赋值运算符1、简介C++允许类对象赋值,这是通过⾃动为类重载赋值运算符实现的,这种运算符的原型如下:Class_name & Class_name::operator=(const Class_name &);它接受并返回⼀个指向类对象的引⽤。
例如,String类的赋值运算符的原型如下:String & String::operator=(const String &);2、何时调⽤将已有的对象赋给另⼀个对象时,将使⽤重载的赋值运算符:String st("123456");String st1;st1=st; //此处使⽤了赋值运算符初始化对象时,并不⼀定会使⽤赋值运算符,如下:String st1=st;st1是新建对象,被初始化为st的值,使⽤了复制构造函数。
复制构造函数与赋值操作符copy constructor 和copy assignment operator调用时间不一样,假设A同时拥有两者,b是A的一个实例:A a(b)与A a=b 调用得失copy constructorA a;a=b;调用的是assignment operator关于copy constructor和copy assignment的细微区别分类:C++2011-05-12 09:39 54人阅读评论(0) 收藏举报//写法1:T c = a+b;//写法2:T c;c = a+b;对于写法1,编译器会产生一个临时对象,放置a+b。
然后调用c的copy constructor把临时对象当做c的初始值://编译器附加代码:T _temp; //产生临时对象_temp = a+b; //放置a+b的值T c(_temp); //调用c的copy constructor还有一种可能是直接以拷贝构造的方式,将a+b的值放到c中。
T c(a+b);或者实行NRV优化:_result.T::T();//直接计算_result...C++standard允许编译器厂商有完全的自由度,但是由于市场的竞争,几乎保证任何表达式如果有这种形式:T c = a+b;那实现时根本不需要产生一个临时对象。
但是对于写法2,不能忽略临时对象。
它会导致下面结果:T temp;temp.operator+(a,b);c.operator=(temp);temp.T::~T();注意,此时在写法1中的"直接以拷贝构造方式来去除临时对象"或"以NRV优化来消除临时对象"的方法被作用于临时对象temp上。
导致只能消除T temp = a+b此表达式的临时对象,而真正的临时对象temp无法被消除。
不管哪一种情况,直接传递c到运算符函数是有问题的。
由于运算符函数并不为外加参数调用一个destructor(它期望一块新鲜的内存),所以必须在此调用前先调用destructor。
C++中的拷贝构造、赋值构造函数C++中的拷贝构造、赋值构造函数C++中的拷贝构造,赋值构造的形式如下:eg:A (A &a) {this->x = a.x;this->y = a.y;cout << "这是⼀个拷贝构造函数" << endl;}A(const A &a) {this->x = a.x;this->y = a.y;cout << "这是⼀个拷贝构造函数" << endl;}A &operator = (const A &a) {this->x = a.x;this->y = a.y;cout << "这是⼀个赋值构造函数" << endl;}对象以值传递⽅式从函数返回时,若接受返回值的对象已经初始化过,则会调⽤赋值构造函数,且该对象还会调⽤析构函数,当对象中包含指针时,会使该指针失效,因此需要重载赋值构造函数,使⽤类似深拷贝或移动构造函数的⽅法赋值,才能避免指针失效。
拷贝构造测试#include<bits/stdc++.h>using namespace std;class A {public:int *x;int y;A();A (A &a) {this->x = a.x;this->y = a.y;cout << "这是⼀个拷贝构造函数" << endl;}A(const A &a) {this->x = a.x;this->y = a.y;cout << "这是⼀个使⽤了const的拷贝构造函数" << endl;}A &operator = (const A &a) {this->x = a.x;this->y = a.y;cout << "这是⼀个赋值构造函数" << endl;}A (int t) {x = new int(0);y = t;printf("address: %x, point:%x, val: %d\n", this, x, y );}~A() {printf("delete %x\n", this);}};void func(A ret) {printf ("传值:stack address: %x, point: %x, value: %d\n", &ret, ret.x, ret.y);}A get() {A ret(3);printf ("从函数返回时stack address: %x, point: %x, value: %d\n", &ret, ret.x, ret.y);return ret;}int main() {A a(1);A c = a;printf ("C的:global address: %x, point: %x, value: %d\n", &c, c.x, c.y);func(c);A d = get();printf ("D的:global address: %x, point: %x, value: %d\n", &d, d.x, d.y);return 0;}测试结果address: 89fed0, point:fb1698, val: 1这是⼀个拷贝构造函数C的:global address: 89fed8, point: fb1698, value: 1这是⼀个拷贝构造函数传值:stack address: 89fee0, point: fb1698, value: 1delete 89fee0address: 89fee8, point:fb1798, val: 3从函数返回时stack address: 89fee8, point: fb1798, value: 3D的:global address: 89fee8, point: fb1798, value: 3delete 89fee8delete 89fed8delete 89fed0赋值构造测试#include<bits/stdc++.h>using namespace std;class A {public:int *x;int y;A() = default;// A (const A &a) {// this->x = a.x;// this->y = a.y;// cout << "这是⼀个const赋值构造函数" << endl;// }A &operator = (const A &a) {this->x = a.x;this->y = a.y;cout << "这是⼀个赋值构造函数" << endl;}A (int t) {x = new int(0);y = t;printf("address: %x, point:%x, val: %d\n", this, x, y );}~A() {printf("delete %x\n", this);}};void func(A ret) {printf ("传值:stack address: %x, point: %x, value: %d\n", &ret, ret.x, ret.y);}A f () {A ret (3);printf ("stack address: %x, point: %x, value: %d\n", &ret, ret.x, ret.y);return ret;}int main() {A c;c = f();printf ("global address: %x, point: %x, value: %d\n", &c, c.x, c.y);A a(1);A d = a;printf ("global address: %x, point: %x, value: %d\n", &d, d.x, d.y);return 0;}测试结果address: 89fee8, point:f51788, val: 3stack address: 89fee8, point: f51788, value: 3这是⼀个赋值构造函数delete 89fee8global address: 89fed8, point: f51788, value: 3address: 89fee0, point:f51698, val: 1global address: 89fee8, point: f51698, value: 1delete 89fee8delete 89fee0delete 89fed8C++中拷贝赋值函数的形参能否进⾏值传递?形参进⾏值传递:A( A);不能。
拷贝构造函数和赋值函数拷贝构造函数和赋值函数是C++中两个重要的函数,它们都是用来复制对象的。
拷贝构造函数用于创建一个新对象并将其初始化为另一个对象的副本,而赋值函数则用于将一个对象的值赋给另一个对象。
在本文中,我们将详细讨论这两个函数的作用和使用方法。
一、拷贝构造函数拷贝构造函数是一个特殊的构造函数,它用于创建一个新对象并将其初始化为另一个对象的副本。
当我们使用一个对象来初始化另一个对象时,拷贝构造函数就会被调用。
例如:```class MyClass {public:MyClass(); // 默认构造函数MyClass(const MyClass& other); // 拷贝构造函数// ...};MyClass obj1; // 调用默认构造函数MyClass obj2(obj1); // 调用拷贝构造函数```在上面的代码中,当我们使用obj1来初始化obj2时,拷贝构造函数就会被调用。
拷贝构造函数的参数是一个常量引用,它表示要复制的对象。
在拷贝构造函数中,我们可以使用另一个对象的数据来初始化新对象的数据成员,从而创建一个新的对象。
需要注意的是,如果我们没有定义拷贝构造函数,编译器会自动生成一个默认的拷贝构造函数。
这个默认的拷贝构造函数会将一个对象的数据成员逐个复制到另一个对象中。
但是,如果我们的类中有指针类型的数据成员,那么默认的拷贝构造函数可能会出现问题,因为它只是简单地复制指针的值,而不是复制指针所指向的对象。
这时,我们就需要自己定义拷贝构造函数来保证正确的复制。
二、赋值函数赋值函数是用于将一个对象的值赋给另一个对象的函数。
当我们使用一个对象来赋值给另一个对象时,赋值函数就会被调用。
例如:```class MyClass {public:MyClass& operator=(const MyClass& other); // 赋值函数// ...};MyClass obj1, obj2;obj2 = obj1; // 调用赋值函数```在上面的代码中,当我们将obj1赋值给obj2时,赋值函数就会被调用。
83 第40卷 第5期 湖南科技学院学报 V ol.40 No.5 2019年5月 Journal of Hunan University of Science and Engineering May.2019C++中复制构造函数与赋值运算符函数研究史小飞2 宫彦军1(1.湖南科技学院 图书馆,湖南 永州 425199;2.湖南科技学院 电子与信息工程学院,湖南 永州 425199) 摘 要:C++中,类中存在常数据成员情况下,需要对赋值运算符函数进行重新定义,不能用系统提供的默认赋值运算符函数,否则使用赋值时存在语法错误。
在类数据成员中存在指针的情况下,需要对复制构造函数和赋值运算符函数进行重新定义,否则在进行复制和赋值时,对象之间的指针指向同一个内存,对象数据之间会存在关联。
关键词:构造函数;复制构造函数;赋值运算符中图分类号:G642.0 文献标识码:A 文章编号:1673-2219(2019)05-0083-031 引 言文[1]对C++中的复制构造函数进行研究,介绍复制构造函数在什么情况下被调用。
拷贝构造函数的作用是用一个已有的对象初始化一个新的对象[2]。
文[3]研究C++的虚拟继承状态下的对象复制语义学。
“对象赋值”是2个已定义的对象,一个对象给另外一个对象赋值[4]。
文[5]对拷贝构造函数和赋值运算符函数进行比较。
文[6]研究赋值,返回引用可以实现连续赋值。
C++中类在存在常数据成员情况下,需要对赋值运算符函数进行重新定义,否则,赋值时会存在语法错误,给出验证的程序代码。
在数据成员中存在指针的情况下,需要对复制构造函数和赋值运算符函数进行自定义,否则在复制和赋值时,对象的数据之间存在关联,一个对象数据的改变会改变另外一个对象的数据,文中给出验证的代码。
2 类有常数据成员情况下的赋值运算常数据成员的值不能改变,通过构造函数进行初始化。
存在常数据成员的情况下,一个对象给另外一个对象赋值,如果不对赋值运算符函数进行自定义,调用系统默认的赋值运算符函数,是把一个对象的所有成员给另外一个对象的所有成员进行对应的赋值,这时,常数据成员也会赋值,因此常数据成员被改变,存在矛盾。
由此可以推断,如果存在常数成员,赋值运算符函数必须进行自定义,否则在使用赋值时会出现语法错误。
看下面类含有常数据成员的代码。
收稿日期:2019-01-18基金项目:永州市指导性科技创新及应用研究项目(永科发(2016)32号)。
作者简介:史小飞(1970-),女,吉林梨树人,助理馆员,研究方向为图书馆学、情报学、计算机程序开发。
通讯作者:宫彦军(1969-),男,吉林公主岭人,湖南科技学院教授,博士,研究方向为目标与环境的电磁散射与光散射特性、电磁(光)波传播与散射、遥感图像分析与处理。
#include <iostream.h> class Cuboid {public:Cuboid(int hi=5,int wi =6,int li=7); int V( ); private:const int h; int w; int l;};Cuboid::Cuboid(int hi,int wi,int li):h(hi) { w=wi; l=li; } int Cuboid::V( ){ return(h*w*l);}//返回体积 int main( ){Cuboid cuboid1(6,9,10),cuboid2;//定义两个cuboid 对象 cout<<"第一个的体积:"<<cuboid1.V( )<<endl; cuboid2=cuboid1; //将cuboid1的值赋给cuboid2cout<<"第二个体积:"<<cuboid2.V( )<<endl; return 0; }对上面代码进行编译,结果如图1所示。
图1.含有常数据成员的代码编译结果从图1可以看出,在类存在常数据成员情况下,赋值运算符函数没有进行自定义,在执行赋值时,存在语法错误。
DOI:10.16336/43-1459/z.2019.05.032把上面的代码增加自定义赋值运算符函数,代码如下。
#include <iostream.h>class Cuboid{public:Cuboid(int hi=5,int wi =6,int li=7);Cuboid& operator=(const Cuboid &t)//赋值运算符函数{w=t.w; l=t.l; return *this; }int V( );private:const int h; int w; int l;};Cuboid::Cuboid(int hi,int wi,int li):h(hi){ w=wi; l=li; }int Cuboid::V( ){ return(h*w*l);}//返回体积int main( ){Cuboid cuboid1(6,9,10),cuboid2;//定义两个cuboid对象 cout<<"第一个的体积:"<<cuboid1.V( )<<endl;cuboid2=cuboid1; //将cuboid1的值赋给cuboid2cout<<"第二个体积:"<<cuboid2.V( )<<endl;return 0; }对上面代码进行编译,结果如图2所示。
图2.增加自定义赋值运算符函数的编译结果从图2可以看出,增加自定义赋值运算符函数之后,类有常数据成员的情况下,在执行赋值时,不存在语法错误。
一个对象可以给另外一个对象赋值,自定义赋值运算符函数的函数里面,没有进行常数据成员的赋值。
3 类的数据成员含有指针下面的代码中,类的数据成员含有指针。
#include <iostream.h>class shixiaofei{public:shixiaofei(int n=10){N=n;if(n>0)gongyanjun=new int[N];else gongyanjun=NULL;}void input(){int i; cout<<"请输入"<<N<<"个整型数:";for (i=0;i<N;i++)cin>>gongyanjun[i];}void output(){int i;for (i=0;i<N;i++)cout<<gongyanjun[i]<<" "; cout<<endl;} private:int N; i nt *gongyanjun;};int main(){ shixiaofei sxf(3);sxf.input();cout<<"sxf:";sxf.output();shixiaofei t=sxf;//复制t.input();cout<<"t:"; t.output();cout<<"sxf:";sxf.output();shixiaofei t1(3);t1=sxf;//赋值cout<<"t1:";t1.output();sxf.input();cout<<"sxf:";sxf.output();cout<<"t1:"; t1.output();return 0;}以上的代码的运行结果如下。
图3.类数据成员含有指针的运行结果(没有自定义复制构造函数和赋值运算符函数)“shixiaofei t=sxf;”调用默认的复制构造函数,从图3可以看出,t的数据输入为5、6、7,sxf的数据也由1、2、3改变为5、6、7。
“t1=sxf;”为赋值,sxf给t1赋值,调用默认的赋值运算符函数,t1的数值为5、6、7,sxf由5、6、7改变为8、9、10,t1也由5、6、7改变为8、9、10。
说明调用默认的复制构造函数和赋值运算符函数,类数据成员含有指针的对象在执行复制和赋值操作时,对象数据之间会存在关联。
8485把上面的代码增加自定义复制构造函数和赋值运算符函数,代码如下。
#include <iostream.h> class shixiaofei { public:shixiaofei(int n=10){ N=n;if(n>0)gongyanjun=new int[N];else gongyanjun=NULL;}//自定义复制构造函数 shixiaofei(shixiaofei &t){ N=t.N;gongyanjun=new int[N]; for(int i=0;i<N;i++)gongyanjun[i]=t.gongyanjun[i];} //自定义赋值运算符函数shixiaofei& operator=(const shixiaofei &t){ N=t.N;if(gongyanjun!=NULL)delete[]gongyanjun; gongyanjun=new int[N]; for(int i=0;i<N;i++)gongyanjun[i]=t.gongyanjun[i]; return *this;} void input(){int i; cout<<"请输入"<<N<<"个整型数:"; for (i=0;i<N;i++)cin>>gongyanjun[i];} void output(){ int i; for (i=0;i<N;i++)cout<<gongyanjun[i]<<" "; cout<<endl;} private:int N; i nt *gongyanjun;}; int main() {shixiaofei sxf(3);sxf.input();cout<<"sxf:";sxf.output();shixiaofei t=sxf;//调用复制构造函数t.input();cout<<"t:"; t.output(); cout<<"sxf:"; sxf.output();shixiaofei t1(3);t1=sxf;//赋值cout<<"t1:";t1.output(); sxf.input();cout<<"sxf:";sxf.output(); cout<<"t1:"; t1.output();return 0;}图4.类数据成员含有指针的运行结果 (有自定义复制构造函数和赋值运算符函数) “shixiaofei t=sxf;”调用自定义的复制构造函数,数据成员含有指针,从图4可以看出,t 的三个数据输入为5、6、7,sxf 的数据保持1、2、3没变。