• 网络学院
  • IT资讯
  • 操作系统
  • 网络技术
  • 软件应用
  • 办公软件
  • 编程技术
  • 网站架设
  • 数据库类
  • 平面设计
  • 多媒体类
  • 游戏资讯
  • 教学论文
  • 认证考试
谈谈c++的初始化工作(下)
  站点:
  • 首 页
  • 最新软件
  • 文章教程
  • 国内软件
  • 国外软件
  • 绿色软件
  • 源码下载
  • 字体下载
谈谈c++的初始化工作(下)
软件发布 谈谈c++的初始化工作(下)
网络软件 系统工具 应用软件 联络聊天 图形图像 多媒体类 行业软件 游戏娱乐 编程开发 安全相关 教育教学 数码软件 绿软下载
热门软件: QQ 瑞星 pplive e话通 木马克星 千千静听 office2000 五笔字根 Photoshop 视频分割
返回文章教程首页 >> 文章首页 >> 认证考试 >> 程序员 >> 谈谈c++的初始化工作(下)

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

添加时间: 2007-4-9 0:05:22  作者: 程序员认证参考  阅读次数:38   来源: http://www.d9soft.com

       

 
    把(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

//默认的构造函数
Human::Human(void)
{
}

Human::~Human(void)
{
}

写一个主文件测试。
但调试出错,错误信息文件为:
/*----------------------------------------------------------------------------
//Human:error file
------ 已启动生成:项目:TestInit, 配置:Debug Win32 ------

正在编译...
Human.cpp
Human.cpp(5) : error C2758: “Human::name” : 必须在构造函数基/成员初始值设定项列表中初始化
e:NETSmall_codeTestInitHuman.h(13) : 参见“Human::name”的声明
Human.cpp(5) : error C2758: “Human::ID” : 必须在构造函数基/成员初始值设定项列表中初始化
e:NETSmall_codeTestInitHuman.h(14) : 参见“Human::ID”的声明
fmain.cpp
Date.cpp
正在生成代码...

生成日志保存在“file://e:NETSmall_codeTestInitDebugBuildLog.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

Human::Human(int id,char *_name):ID(id)
{
name=new Name(_name);//初始化:指针
}

Human::~Human(void)
{
delete name;//析构时释放资源
}

//fmain.cpp
#include
#include "human.h"

void main()
{
//测试程序
try{
Human lily(11100120,"lily");
Human lucy=lily;
}
catch(...)
{//如果有any异常
std::cout<<" Unknown Exception... ";
}

}

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


事实上,调试过程中,等三个异常忽略后,就会得到下面的结果:
/*
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
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
#include "human.h"
void main()
{
using namespace Humanbeing;
try{
Human lily(11100120,"lily");
Human lucy=lily;

if(IsSameMan(lucy,lily))
{
std::cout<<" They are the same one. ";
}else
std::cout<<" No,they're not the same one. ";

}
catch(...)
{
std::cout<<" Unknown Exception... ";
}

}


调试结果呢,是连续六个异常后,出现:
After six exceptions occured you get :

They are the same one.

Unknown Exception...
Press any key to continue

 

上下文章:

 

上一篇文章: 赛迪网校11月软考模拟试题程序员上午 下一篇文章: C++大师Lippman:我对中国程序员的忠告

相关文章:

  • 如何获得Oracle DBA工作?
  • 无线路由器常见工作异常情况分析
  • 无线路由器工作异常疑难详解
  • 反黑入门 搞懂特洛伊木马工作原理
  • 谈谈学习方法和ccna的重要性

相关软件:

  • 手机主题工作室 0.96
  • WorkLog 工作日志管理 3.18
  • 81238工作室Wap手机电影 v1.0
  • 珊瑚工作室全国计算机等级考试三级数据库 考试系统 5.1
  • 珊瑚工作室全国计算机等级考试三级网络技术 考试系统 V5.1
  • 珊瑚工作室全国计算机等级考试三级信息管理考试系统 V 5.1

 

快速导航

  • 网络学院
  • 精品汇聚
  • 字体下载
  • 教程下载
  • ASP源码
  • PHP源码
  • Net源码
  • JSP 源码

认证考试分类导航

  • 微软认证
  • 计算机等级考试
  • 软件水平考试
  • 思科认证
  • Oracle认证
  • Linux认证
  • JAVA认证
  • 网络工程师
  • 系统工程师
  • 程序员

本类经典文章推荐

  • 软考系统分析师考试须知
  • C++箴言:绝不在构造或析构期调用...
  • 数据结构:判别是否为二叉排序树的...
  • 一个程序员的成长的六个阶段
  • 程序员英语试题常见硬件名和设备名
  • 从一个程序出发详细研究DataReader
  • 如何判断程序处于运行环境还是调试...
  • 程序高手必读:写好C程序的10条秘...
  • 程序员介绍:程序员的“素质”是什...
  • C++箴言:让=返回一个*this的引用

程序员阅读排行

  • 数据结构:判别是否为二叉排序树的...
  • VC++动态链接库(DLL)编程深入浅出...
  • VC++动态链接库(DLL)编程深入浅出...
  • 程序员考试:证书样本
  • 补码加、减运算规则及溢出判断
  • 数据结构:栈和递归求两顶点所有简...
  • DirectX8.0简介(8)
  • 水滴石穿·C语言之代码检查工...
  • 数据结构:打印线索二叉树的中序遍...
  • DirectX8.0简介(3)

认证考试阅读总排行

  • 全国计算机等级考试一级模拟试题01
  • 全国计算机等级考试一级模拟试题10
  • 全国计算机等级考试一级模拟试题08
  • MCSD简介
  • 全国计算机等级考试一级考试最新模...
  • 全国计算机等级考试一级模拟试题07
  • 全国计算机等级考试一级模拟试题02
  • 全国计算机等级考试一级模拟试题06
  • 全国计算机等级考试一级模拟试题03
  • 一级(WINDOWS)试题解析-Word篇

广告位置

字母检索 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 回到顶部

关于我们 | 版权声明 | 免责条款 | 广告联系 | 软件发布 | 下载帮助 | 下载排行 | 网站地图 | 特别鸣谢 | 友情连接

copyright; 2005-2008 D9soft.com 第九软件网 版权所有