C类中的4个特殊函数缺省构造函数拷贝构造函数拷贝赋值操作.docx

上传人:b****8 文档编号:30146167 上传时间:2023-08-05 格式:DOCX 页数:13 大小:17.15KB
下载 相关 举报
C类中的4个特殊函数缺省构造函数拷贝构造函数拷贝赋值操作.docx_第1页
第1页 / 共13页
C类中的4个特殊函数缺省构造函数拷贝构造函数拷贝赋值操作.docx_第2页
第2页 / 共13页
C类中的4个特殊函数缺省构造函数拷贝构造函数拷贝赋值操作.docx_第3页
第3页 / 共13页
C类中的4个特殊函数缺省构造函数拷贝构造函数拷贝赋值操作.docx_第4页
第4页 / 共13页
C类中的4个特殊函数缺省构造函数拷贝构造函数拷贝赋值操作.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

C类中的4个特殊函数缺省构造函数拷贝构造函数拷贝赋值操作.docx

《C类中的4个特殊函数缺省构造函数拷贝构造函数拷贝赋值操作.docx》由会员分享,可在线阅读,更多相关《C类中的4个特殊函数缺省构造函数拷贝构造函数拷贝赋值操作.docx(13页珍藏版)》请在冰豆网上搜索。

C类中的4个特殊函数缺省构造函数拷贝构造函数拷贝赋值操作.docx

C类中的4个特殊函数缺省构造函数拷贝构造函数拷贝赋值操作

a.C++标准中提到“Thedefaultconstructor,copyconstructorandcopyassignmentoperator,anddestructorarespecialmemberfunctions.[Note:

Theimplementationwillimplicitlydeclarethesememberfunctionsforsomeclasstypeswhentheprogramdoesnotexplicitlydeclarethem.Theimplementationwillimplicitlydefinethemiftheyareused.]”。

即缺省构造函数、拷贝构造函数、拷贝赋值操作符和析构函数是特殊成员函数。

 

b.“Constructorsdonothavenames.Aspecialdeclaratorsyntaxusinganoptionalsequenceoffunction-specifiers(inline,virtualandexplicit)followedbytheconstructor’sclassnamefollowedbyaparameterlistisusedtodeclareordefinetheconstructor.”构造函数没有名称。

 

c.构造函数不能有返回类型,也不能由virtual,const,static和volatile来修饰。

但可以由inline来修饰,事实上隐式构造函数就是用inline来修饰的。

inline表示编译时展开,通常速度块;virtual表示运行时绑定,通常意味着灵活。

 

d.类中存在虚函数或者有虚基类的情况下需要显式声明构造函数。

拷贝构造函数也是如此。

 

f.构造函数是一种特殊函数,而拷贝构造函数是一种特殊的构造函数。

类X的构造函数的第一个参数必须为X&,或者constX&;除了第一个参数外,构造函数要么不存在其他参数,如果存在其他参数,其他参数必须有默认值。

一个类可以有多个拷贝构造函数。

它的形式如下:

X:

:

X(X&x)

X:

:

X(constX&x)

X:

:

X(X&x,inta=0,intb=1…)

 

g.什么时候会调用拷贝构造函数?

以下三种情况出现时,会调用一个类的拷贝构造函数:

1)用一个已经实例化了的该类对象,去实例化该类的另外一个对象;

2)用该类的对象传值的方式作为一个函数的参数;

3)一个函数返回值为该类的一个对象。

 

运行下面代码以验证之:

#include

usingnamespacestd;

 

classCA

{

public:

inta;

intb;

public:

inlineCA()

{

a=1;

b=1;

}

 

inlineCA(intA,intB)

{

a=A;

b=B;

}

 

inlineCA(CA&x)

{

a=x.a;

b=x.b;

cout<<"copyconstructoriscalled."<

}

 

voidprintInfo()

{

cout<<"a="<

}

};

 

intsomeFun1(CAx)

{

returnx.a+x.b;

}

 

CAsomeFun2(inta,intb)

{

CAca(a,b);

returnca;

}

 

intmain(void)

{

CAa;

//CAb();//不能用这种方式声明CA的对象b!

CAc(10,10);

 

CAd(c);//情况1)->调用拷贝构造函数

intanInt=someFun1(c);//情况2)->调用拷贝构造函数

CAe=someFun2(11,11);//情况3)->调用拷贝构造函数

 

return0;

}

运行结果:

运行结果表明,上述结论是正确的。

 

h.什么时候必须要显式声明拷贝构造函数?

拷贝构造函数的作用就是用一个已经实例化了的该类对象,去实例化该类的另外一个对象。

 

1)下面的代码并没有显式声明一个构造函数,编译器会自动为类CExample1生成一个缺省的隐式拷贝构造函数:

#include

usingnamespacestd;

 

classCExample1

{

private:

inta;

 

public:

CExample1(intb){a=b;}

voidSetValue(inta){this->a=a;}

voidShow(){cout<

};

 

intmain(void)

{

CExample1A(100);

CExample1B=A;//调用了缺省的隐式拷贝构造函数

CExample1C(B);//调用了缺省的隐式拷贝构造函数

 

B.Show();//输出应该是100

B.SetValue(90);

B.Show();//输出应该是90

A.Show();//输出应该是100

C.Show();//输出应该是100

 

return0;

}

输出为:

 

2)如果有成员变量以指针形式存在,涉及动态内存分配等情况下,一定要显式声明拷贝构造函数。

要注意到,如果需要显式定义拷贝构造函数,那么通常都是需要同时定义析构函数(因为通常涉及了动态内存分配),至于是否必须重载操作符“=”,要视情况而定。

 

#include

usingnamespacestd;

 

classCSomething

{

public:

inta;

intb;

 

public:

CSomething(inta,intb)

{this->a=a;this->b=b;}

};

 

classCA

{

private:

CSomething*sth;//以指针形式存在的成员变量

 

public:

CA(CSomething*sth){this->sth=newCSomething(sth->a,sth->b);}

~CA()

{

cout<<"InthedestructorofclassCA..."<

if(NULL!

=sth)deletesth;

}

voidShow(){cout<<"("<a<<","<b<<")"<

voidsetValue(inta,intb){sth->a=a;sth->b=b;}

voidgetSthAddress()

{

cout<

}

};

 

intmain(void)

{

CSomethingsth(1,2);

CAca(&sth);

ca.Show();

 

CAcb(ca);//调用缺省的隐式拷贝构造函数

cb.Show();

 

cb.setValue(2,3);

ca.Show();

cb.Show();

 

ca.getSthAddress();

cb.getSthAddress();

 

return0;

}

上面的程序没有显式声明拷贝构造函数,运行结果如下:

 

可见,ca和cb中的指针成员变量sth指向的是同一个内存地址(Console输出的第5、6行),这就是为什么在cb.setValue(2,3)后,ca对应的内容也发生了改变(Console输出的第3、4行),而这不是我们所期望的;其次,我们生成了两个对象ca和cb,因此对两次调用析构函数,第一次调用析构函数的时候没有问题,因为此时sth里面有内容,第二次调用析构函数时,sth里面的内容由于在第一次调用析构函数的时候已经被delete了,所以会出现如上的错误提示。

 

保持其他代码不变,现在我们增加一个拷贝构造函数如下:

CA(CA&obj)

{

sth=newCSomething((obj.sth)->a,(obj.sth)->b);

}

再运行上面的程序,所得到的结果如下:

 

这次,ca和cb中的指针成员变量sth指向的不是同一个内存地址(Console输出的第5、6行)了,这就是为什么在cb.setValue(2,3)后,ca对应的内容保持不变,而cb的内容该如愿地改为(2,3)(Console输出的第3、4行);其次,析构函数也不会报告错误了。

 

3)关于拷贝构造函数另外一个完整的例子,其中包含了copyconstructor,destructor和copyassignmentoperator。

#include

usingnamespacestd;

 

classPoint

{

public:

int_x;

int_y;

 

public:

Point();

Point(int,int);

};

 

Point:

:

Point()

{

_x=0;

_y=0;

}

 

Point:

:

Point(intx,inty)

{

_x=x;

_y=y;

}

 

classCA

{

public:

Point*_point;

 

public:

CA(constPoint*);

voidsetPointValues(int,int);

voidprintCoordinates();

 

//需要增加的拷贝构造函数

CA(constCA&);

//需要增加的析构函数

virtual~CA();

//需要增加的拷贝赋值函数

CA&operator=(constCA&);

};

 

CA:

:

CA(constPoint*point)

{

_point=newPoint();//发生了动态内存分配!

因此不能缺少析构函数。

_point->_x=point->_x;

_point->_y=point->_y;

}

 

//需要增加的拷贝构造函数的实现

CA:

:

CA(constCA&ca)

{

_point=newPoint();

_point->_x=(ca._point)->_x;

_point->_y=(ca._point)->_y;

}

 

//需要增加的析构函数的实现

CA:

:

~CA()

{

if(!

_point)delete_point;

}

 

//需要增加的拷贝赋值函数的实现

CA&CA:

:

operator=(constCA&ca)

{

_point=newPoint();

_point->_x=(ca._point)->_x;

_point->_y=(ca._point)->_y;

 

return*this;

}

 

voidCA:

:

setPointValues(intx,inty)

{

_point->_x=x;

_point->_y=y;

}

 

voidCA:

:

printCoordinates()

{

cout<<"Coordinates=("<<_point->_x<<","<<_point->_y<<")"<

}

 

intmain(void)

{

Pointapoint(1,2);

CAca(&apoint);

ca.printCoordinates();

 

CAcb(ca);//调用拷贝构造函数

cb.printCoordinates();

 

cb.setPointValues(12,12);

cb.printCoordinates();

ca.printCoordinates();

 

CAcc=cb;//调用拷贝赋值函数

cc.printCoordinates();

cc.setPointValues(13,13);

ca.printCoordinates();

cb.printCoordinates();

cc.printCoordinates();

 

return0;

}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 农林牧渔 > 畜牧兽医

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1