分享
 
 
 

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

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

我们还是先来看看上次遗留的问题。“为什么(上次异常是三个,这次是六个,可以解释吗)?怎么办?”这其中的原因,我想您是明白的,我只做简单的重复:)。代码段中:

//bool IsSameMan(Human one,Human another)

if(IsSameMan(lucy,lily))//(1)

{

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

}else

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

}

(1)句传入两个对象(lucy,lily),根据Human类的定义,系统试图把它们的资源分别复制给one和 another,但毫无疑问出现了浅拷贝的问题。当局部对象one和another析构时,问题表现出来了。至于为什么是六个异常,呵呵,还是您来回答吧?

知道原因,就容易解决。我们需要一个拷贝构造函数,来完成这项资源拷贝的工作,如下:

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

Human(Human &human):ID(human.getID())

{

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

}

OK,and you get :

They are the same one.

Press any key to continue

就没问题了。

这次,我们来看看组合与继承中的初始化问题,最后再说明对象数组初始化需要注意的地方。主要是继承的例子。我想澄清一些想法,强调一些观念。当然,如果有争议的地方,欢迎您给我指出。先谢过了。

大家知道,组合与继承都是非常重要的耦合方式。典型的组合与继承的例子,分别如下:

class Point{

int x,y;

//...

public:

//...

};

class Shape{

protected:

Point p0; //组合

//...

public:

Shape(int x,int y);

Shape(Point &point);

//...

};

class Window:public Shape{ //继承

int width,height;

//...

public:

Window(int _x,int _y,int _w,int _h);

//...

};

在初始化时,可能是这样的:

Window::Window(int _x,int _y,int _w,int _h):Shape(_x,_y),width(_w),height(_h)

{ } //(1)

组合与继承的初始化,如果是我们自己来做这项工作,初始化的时机可只有这一个,(1)冒号后。这是c++的语法,没有什么可说的。

但是,我想,到现在,有些认识,需要得到强调。

首先,c++中的对象创建时必须得到初始化。一般的,我们要自己来做这项工作;但如果您没有给出自己的构造函数,系统会给一个默认的构造函数,并去调用它(您知道它会做些什么吗?)。初始化是必须保证的。

其次,复杂类(组合继承迩来)的初始化工作中,构造函数调用有固定的顺序。一般的c++教材都说的很详细,我就不多说了。

但有趣的是,复杂类中,若出现默认的系统初始化,都会发生些什么?如果所有的父类都没有写构造函数,成员对象的类也没有写构造函数,又没有常量成员和引用成员,一系列的初始化工作是按原来的顺序执行,还是没有初始化?这个问题也许没有实际意义,但对理解初始化工作是很有意义的,我认为。

我们以继承的初始化为例子,一步一步来看。

我们先来看看,如果不写构造函数,系统会做什么。

类的定义。首先,Shape是一个抽象基类(接口)。我没有为它写任何构造函数,让系统来吧。

//shape.h

#pragma once

class Shape

{

protected:

int x,y;

public:

virtual ~Shape(void);

virtual void SetXY(int _x,int _y) = 0;

};

//shape.cpp

#include "shape.h"

#using <mscorlib.dll>

#include <stdlib.h>

Shape::~Shape(void)

{

}

下面是Shape类的一个子类实现,Window。为了对比测试,它有两个构造函数,一个是无任何参数,不做任何事情,当然,我们可以假设不知道它会不会调用父类Shape的构造函数。另一个是正常的构造函数,但从父类

继承的成员没有在其中初始化(看系统如何做)。

//window.h

#pragma once

#include "shape.h"

class Window :

public Shape

{

int width,height;

public:

Window(void);

Window(int _x,int _y,int _w,int _h);

virtual ~Window(void);

virtual void SetXY(int _x, int _y);

void Test(void);

};

//window.cpp

#include<iostream>

//构造函数1

Window::Window(void)

{

}

//构造函数2

Window::Window(int _x,int _y,int _w,int _h)

{

width=_w;

height=_h;

}

Window::~Window(void)

{

}

void Window::SetXY(int _x, int _y)

{

x=_x;

y=_y;

}

//

void Window::Test(void)

{

std::cout<<"x="<<x<<",y="<<y<<",width="<<width<<",height="<<height<<"\n\n";

}

这是公共的测试文件:

//fmain.cpp

#include <iostream>

#include "window.h"

void main()

{

Window win2;

std::cout<<"Test:win2:\n";

win2.Test();

Window win(10,10,50,50);

std::cout<<"Test:win:\n";

win.Test();

}

执行,结果如下:

Test:win2:

x=1243328,y=1243040,width=1303984,height=1243296

Test:win:

x=1243040,y=1,width=50,height=50

Press any key to continue

win2调用的是构造函数1,win调用的是构造函数2。win2的所有成员,值都似乎是随机给的。而win中,只有width和height达到了预期效果,x和y和win2没有什么区别!

暂行记住,这是没有写构造函数的结果。

我们现在给Shape类添加构造函数,有两个版本,作用同于上面Window类的构造函数。如下:

//shape.h

#pragma once

class Shape

{

protected:

int x,y;

public:

Shape(void);

Shape(int _x,int _y);

virtual ~Shape(void);

virtual void SetXY(int _x,int _y) = 0;

};

//shape.cpp

#include "shape.h"

#using <mscorlib.dll>

#include <stdlib.h>

//构造函数1:什么也不做

Shape::Shape(void)

{

}

//构造函数2:履行初始化工作

Shape::Shape(int _x,int _y)

{

x=_x;

y=_y;

}

Shape::~Shape(void)

{

}

Window类的构造函数相应改正如下:

//构造函数1

Window::Window(void):Shape()

{

}

//构造函数2

Window::Window(int _x,int _y,int _w,int _h):Shape(_x,_y)

{

width=_w;

height=_h;

}

测试文件代码不变。执行,结果如下:

Test:win2:

x=1243328,y=1243040,width=1303984,height=1243296

Test:win:

x=10,y=10,width=50,height=50

Press any key to continue

win2的情况没有改观,但win的初始化就是我们所要的!

这说明了什么?如果您不明白,可以回头对比看看。

系统的默认初始化,即使它给的值,是当时所在的内存地址的所有值(不可预料),但那仍然是初始化!

说到默认初始化,在欲创建对象数组时要特别注意,如果没有确省的构造函数,对象数组是无法创建的,因为没有合适的构造函数可调用!(如果不能初始化,编译器是做出错处理的)

Shape和Window类的构造函数相应改正如下:

//构造函数1:

Shape::Shape(void)

{

x=0;y=0;

}

//构造函数1

Window::Window(void):Shape()

{

width=0;height=0;

}

主函数中代码换为:

Window win[5];

for(int i=0;i<5;i++)

{

std::cout<<"Test:"<<i<<":\n";

win[i].Test();

}

则结果为:

Test:0:

x=0,y=0,width=0,height=0

Test:1:

x=0,y=0,width=0,height=0

Test:2:

x=0,y=0,width=0,height=0

Test:3:

x=0,y=0,width=0,height=0

Test:4:

x=0,y=0,width=0,height=0

Press any key to continue

但是,你把Shape类的构造函数1注释掉(既删除缺省构造函数),再用同样的测试文件编译时,编译出错:

Window.cpp(5) : error C2512: “Shape” : 没有合适的默认构造函数可用

总之我想,这样的观念是必须的:

初始化工作必须完成。任何情况下,系统完成初始化工作的机理是不变的(构造函数调用顺序),系统不会偷懒:)。我们需要设计良好的初始化过程。

这次遗留的问题是,所有的这些问题,在组合的情况下,也会发生吗?在对象数组初始化时,如果我们希望每个对象的初始化状态都不同,应该如何做?如果您感觉不够清晰,愿您能写代码测试一下,跟着结果思考:)。

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