分享
 
 
 

谈谈c++的初始化工作(2)

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

我们首先来看上次遗留的问题。

把(1)中的代码换为注释部分,或许您一时还认识不到会有什么发生,但最终是通不过的,调试抛出异常,信息如下:

未处理的“System.Runtime.InteropServices.SEHException”类型的异常出现在 TestInit.exe 中

其他信息:外部组件发生异常。

This application has requested the Runtime to terminate it in an unusual way.

Please contact the application's support team for more information.

Press any key to continue

我想,您回头再细看的话,就会明白为什么如此了(我们写程序一定要追问到底:)。

我们今天要谈的是,一些变量只有唯一的初始化形式,通过例子,告诉您要特别注意。然后,我们就一步一步,来看资源浅拷贝的问题。我相信初学c++的同学,会对“拷贝函数”有些疑问,它就是为了解决上述问题的;但事实上,还有一个隐藏的地方,今天我也想给您指出。

这些程序,可是我特意设计的哦。希望可以很方便的认识问题所在,与解决之道。

首先,看第一个例子。在类中,这两类变量:

e.g.

Name &name; //引用

const int ID; //常量

它们的初始化形式是唯一的。而且必须由您来初始化。

看下面的程序:

//human.h

#pragma once

class Name

{

char *name;

public:

//...

};

class Human

{

Name &name;

const int ID;//每个人都唯一的标志号

//...

public:

Human(void);

~Human(void);

//...

};

//human.cpp

#include "human.h"

#using <mscorlib.dll>

//默认的构造函数

Human::Human(void)

{

}

Human::~Human(void)

{

}

写一个主文件测试。

但调试出错,错误信息文件为:

/*----------------------------------------------------------------------------

//Human:error file

------ 已启动生成:项目:TestInit, 配置:Debug Win32 ------

正在编译...

Human.cpp

Human.cpp(5) : error C2758: “Human::name” : 必须在构造函数基/成员初始值设定项列表中初始化

e:\NET\Small_code\TestInit\Human.h(13) : 参见“Human::name”的声明

Human.cpp(5) : error C2758: “Human::ID” : 必须在构造函数基/成员初始值设定项列表中初始化

e:\NET\Small_code\TestInit\Human.h(14) : 参见“Human::ID”的声明

fmain.cpp

Date.cpp

正在生成代码...

生成日志保存在“file://e:\NET\Small_code\TestInit\Debug\BuildLog.htm”中

TestInit - 2 错误,0 警告

---------------------- 完成 ---------------------

生成:0 已成功, 1 已失败, 0 已跳过

--------------------------------------------------------------------------------

*/

因为这里涉及的是仅仅的c++语法,我就不多费口舌了,如何改正,希望您能动手试试,一定要动手,不要想当然哦~~~

当然,如果您是爱问题的人,我想您可以这样深究一下:设计c++语言时,为什么诸如int类型成员变量能提供默认初始化,而它们却不能;从编译角度,刻意给它们提供如int类型般的初始化会有什么困难和问题?

下面详细谈什么是资源浅拷贝问题。沿袭c的习惯,c++对系统自分配的资源进行统一管理,但是,用户申请的资源,则有用户来释放。

比如:

userType *p=new userType(/*---*/);

//...

delete p;

//delete释放一般是不可忘的

单独的变量或许对您来说是不成问题的。但在类中,这些情况就变的相当复杂。处理不好,您的系统要么就是因为内存泄露而运行不下去,而要么就是异常频频发生。

我们先来看一些c++的默认操作:

//...

class OneClass {

int _value;

public:

OneClass(int _val=0):_value(_val) {}

~OneClass() {}

//...

};

//you may use in this way:

OneClass oneObj(7);

OneClass anotherObj;

anotherObj=oneObj;//(1)

//...

//int Compare(OneClass one,OneClass two);

int k=Compare(oneObj,anotherObj);//(2)

//...

在本程序的场景下,上面的代码是可以完好工作的,但您清楚(1)与(2)系统都作了什么了吗?您是否知道,如果您的初始化工作做的不好的话,即使,就沿用上面的初始化习惯,您的程序很容易就崩溃了呢。

答案是,(1)语句执行时,默认的,系统试图把oneObj的资源全部copy给anotherObj,但用户申请的资源(new来的:),却传入的是地址;(2)语句的默认形参传递遵循同样的规则。

当然这与java与c#是不同的,因为java与c#的对象是引用类型。而c++,除非您强行定义为引用类型的,它就不是。

我们来看下面的例子,第一遍我建议您只看程序,不要往下看,看您能否发现什么问题。

//human.h

#pragma once

#define NULL 0

class Name

{

char *name;

public:

Name(char *_name=NULL):name(_name) {}

~Name() { }

char *getName(){ return name;}

};

class Human

{

Name *name;//

int ID; //唯一化标志

public:

Human(int id=0,char *_name=NULL);

~Human(void);

int getID()const { return ID;}

Name *getName() { return name;}

};

//human.cpp

#include "human.h"

#using <mscorlib.dll>

Human::Human(int id,char *_name):ID(id)

{

name=new Name(_name);//初始化:指针

}

Human::~Human(void)

{

delete name;//析构时释放资源

}

//fmain.cpp

#include <iostream>

#include "human.h"

void main()

{

//测试程序

try{

Human lily(11100120,"lily");

Human lucy=lily;

}

catch(...)

{//如果有any异常

std::cout<<"\n Unknown Exception...\n";

}

}

//请回头看程序,您觉得一切都好吗?

事实上,调试过程中,等三个异常忽略后,就会得到下面的结果:

/*

After three exceptions occured you get :

Unknown Exception...

Press any key to continue

*/

为什么?

看这几行代码:

Human lily(11100120,"lily");

Human lucy=lily;

虽然一开始,我就给了小例子,形式一样,那个没问题。何以这个就不行了呢?因为类的定义不同。

由c++工作的机理,这行

Human lucy=lily;

是把lily的资源拷贝给lucy(lucy是不调用构造函数的),可是,因为其中的name是用户申请的资源,并不能把它也拷贝过去,而是直接传了地址。这样,您知道吗,lucy.name和lily.name的地址是一样的。

于是,当一个的析构函数调用后,name所指向的资源已被释放掉了的。而另外一个类的析构函数又去释放,问题来了---程序崩溃了!

这就是浅拷贝问题---“浅”的不完全的拷贝:)。

找到原因,我们就办法。解决的办法是,这份工作自己来做!

写一个拷贝赋值操作(public):

形式为: className &operator=(className &obj){ /*...*/}

您看下面的解决办法和结果:

/*

If you add ...in class Human(public):

Human &operator=(Human &human){

if(this!=&human){

ID=human.getID();

name=new Name(human.getName()->getName());

return *this;

}

}

OK,and you get:

Press any key to continue

That is what we want!

*/

下面的例子,是拷贝函数的问题,在上面的基础上,我改动了一下程序的结构,

定义了一个名空间。

具体的问题分析我留给下次,您就有机会细细的看了。您是否一切都清楚了?

您可以解决这个问题吗?

//human.h

#pragma once

#using <mscorlib.dll>

namespace Humanbeing

{

#define NULL 0

class Name

{

char *name;

public:

Name(char *_name=NULL):name(_name) {}

~Name() { }

char *getName(){ return name;}

};

class Human

{

Name *name; //

int ID; //唯一的标志

public:

Human(int id=0,char *_name=NULL):ID(id)

{

name=new Name(_name);//申请资源

}

~Human(void)

{

delete name;//释放资源

}

//拷贝赋值操作

Human &operator=(Human &human){

if(this!=&human){

ID=human.getID();

name=new Name(human.getName()->getName());

return *this;

}

}

int getID()const { return ID;}

Name *getName() { return name;}

};

//名空间里的函数

bool IsSameMan(Human one,Human another)

{

if(one.getID()==another.getID())

return true;

else return false;

}

}

//测试文件

#include <iostream>

#include "human.h"

void main()

{

using namespace Humanbeing;

try{

Human lily(11100120,"lily");

Human lucy=lily;

if(IsSameMan(lucy,lily))

{

std::cout<<"\n They are the same one.\n";

}else

std::cout<<"\n No,they're not the same one.\n";

}

catch(...)

{

std::cout<<"\n Unknown Exception...\n";

}

}

调试结果呢,是连续六个异常后,出现:

After six exceptions occured you get :

They are the same one.

Unknown Exception...

Press any key to continue

为什么(上次异常是三个,这次是六个,可以解释吗)?怎么办?

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有