分享
 
 
 

由始至终----构造与析构

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

由始至终

----构造与析构

作者:HolyFire

我们在平时的生活中一般会总结出一些规律,早上起床会刷牙洗脸,晚上会洗澡睡觉,这些都成了惯例。使用瓶装调味品时先将瓶盖打开,用完后将瓶盖盖上。这是一种好习惯。但是有些人不同,他们往往偷懒,一个常常不刷牙不洗脸不洗澡的人会有体味,东西放得乱七八糟的人生房间很不整洁。这些都是我们不希望看到的。当然编程中我们也不希望代码乱七八糟。

使用一个未初始化的变量简直就是灾难,使用一个未初始化的指针将导致崩溃。这是我的忠告。在C++中初始化不会有附加的效果,不会降低效率,我们要做的是养成好习惯,产生一个对象的时候就将它初始化。

对于

Object.Init();

Object.Free();

这样的调用并不是很困难,要记住他也不是难事,但是谁都不能保证他永远不会忘记,更糟糕的是

Object.Init();

Object.Free();

没有配对使用

Object.Init();

Object.Free();

Object.Free();

Object.Init();

Object.Init();

Object.Free();

会带来什么样的结果,谁也不知道,而且这样的错误,编译器不会报错。这是多么可怕的错误,一个程序员最怕遇上的就是这样的逻辑错误,它可能为了找这样的一个错误花上一整天时间。

让我们看看有什么好的办法。

一个对象按时间来分析,一般有三个阶段,出生,活动,死亡。与我们要做的有什么相关之处呢,初始化,运行,释放。很好,对照一下,我们发现在对象出生的时候初始化,死亡的时候释放,如果这一切能用这样的机制来操作,我们就再也不用担心会由于忘记或错误的使用带来麻烦了。

C++里就提供了这样的机制。使用他有个约定

class Object{

public:

Object(); //与类同名的函数,该函数没有返回值,叫做构造函数

~Object(); //类似的,在构造函数名前加一个取反符号,叫做析构函数

};

构造函数将在对象产生的时候调用

析构函数将在对象销毁的时候调用

调用的过程和实现方法由编译器完成,我们只要记住他们调用的时间就行了,而且他们的调用是自动完成的,不需要我们控制。

#include <iostream>

using namespace std;

class Object{

public:

Object(){ cout << "Object ON!" << endl; }

~Object(){ cout << "Object OFF!" << endl; }

};

void main()

{

Object o;

}

运行结果

Object ON!

Object OFF!

构在函数和析构函数确实的执行了

现在我们来一个应用的例子

一个字符串类,它需要保存字符串的内容,但是它不知道字符串的大小,那么设计这个字符串类的时候,保存字符串的成员变量就不能用固定大小的数组,而是用可以间接操作数组的指针。

#include <iostream>

#include <string.h>

using namespace std;

class string{

private:

char * data;

public:

string(){ data = NULL; }

string( char * str )

{

cout << "Copy string: " << str << endl;

data = new char[ strlen(str) + 1 ];

memcpy( data , str , strlen(str) + 1 );

}

char * Data(){ return data; }

~string()

{

if( data )

{

cout << "Free string: " << data << endl;

delete data;

}

}

};

void main()

{

{

string s("abcd");

cout <<"Show String: " << s.Data() <<endl;

}

cin.get();

}

Copy string: abcd //执行了string::string( char * str ) 构造函数

Show String: abcd

Free string: abcd //由于在{}中产成的对象是临时对象,它的生命期在}后就结束了,所以string::~string() 析构函数被调用

申请内存和释放内存的操作自动完成了,构造函数和析构函数的目的在于一个类可以象普通类型一样初始化和释放,从而保证了封装。

上面的例子有两个构造函数,这么什么大不了的,我们看过《面面俱到----重载》得都知道,重载的把戏。

要注意的是构造函数可以有参数,在继承中如何处理呢。

class mystring : public string{

public:

mystring( char * str ):string( str ){ }

}

mystring( char * str ):string( str )

记住这样的形式,给自己的父类传递函数就用这样的书写格式,这是一个约定。

构造函数后面加上一个:表示后面是一个初始化序列,说它是一个序列是因为它可以初始化多个成员变量,在初始化序列里调用向父类传递参数是为了保证类的产生的顺序,先产生父类,然后是子类。使用初始化有个好处就是可以提高效率。

string(){ data = NULL; }

可以改写成

string():data(NULL){ }

他的作用是产生成员变量char * data时将他的值置为NULL。从而少了data = NULL;这步操作。

注意,这里构造和析构有一个顺序问题,就是构造时应该从基类开始按继承的层次顺序调用,析构的时候顺序正好相反。这样处理是因为,子类可能在构造函数里使用父类的成员变量,如果父类还没有创建,那就会有问题,而析构的时候,如果父类先析构,也会有这样的问题。

析构函数还有一个能否正确运行的问题。

#include <iostream>

using namespace std;

class One{

public:

One(){ cout << "One ON!" << endl; }

~One(){ cout << "One OFF!" << endl; }

};

class Two : public One{

public:

Two(){ cout << "Two ON!" << endl; }

~Two(){ cout << "Two OFF!" << endl; }

};

class Three : public Two{

public:

Three(){ cout << "Three ON!" << endl; }

~Three(){ cout << "Three OFF!" << endl; }

};

void main()

{

Three three;

}

运行结果

One ON!

Two ON!

Three ON!

Three OFF!

Two OFF!

One OFF!

正确

void main()

{

Three * three = new Three;

delete three;

}

运行结果

One ON!

Two ON!

Three ON!

Three OFF!

Two OFF!

One OFF!

正确

void main()

{

One * three = new Three;

delete three;

}

运行结果

One ON!

Two ON!

Three ON!

One OFF!

不好了,Two和Three的析构都没有运行,怎么会这样,原来One * three指出了指针指向的是一个One类的对象。如何得到正确的结果呢,如果能让One类记住被继承后的变化就好了。

对了!虚函数,在《后入为主----虚函数》中可以知道,虚函数有这个特性,不信试试看。

class One{

public:

One(){ cout << "One ON!" << endl; }

virtual ~One(){ cout << "One OFF!" << endl; }

};

void main()

{

One * three = new Three;

delete three;

}

运行结果

One ON!

Two ON!

Three ON!

Three OFF!

Two OFF!

One OFF!

正确

这个特点很重要,我们要牢牢记住,我们称这种方法为“虚析构”,在多态里运用非常广泛,也是编写可复用代码的一个重要技巧。

构造和析构的作用机制就是自动化,简化编程的复杂度。还有要记住的是,在一个类的构造函数里分配了的资源尽量要记得在该类的析构函数里释放,当然也允许提前释放,你可以在析构函数里判断它是否已经释放,如果没有就释放。这就是----由始至终,它间接的描述了一个对象的生和死(记住这一点很重要,因为我以后会讲到如何运用这个特性控制对象的生死)。

2001/8/23

丁宁

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有