ITPub博客

首页 > 应用开发 > IT综合 > 谈谈c++的初始化工作(3) (转)

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

原创 IT综合 作者:amyz 时间:2007-08-15 14:52:07 0 删除 编辑
谈谈c++的初始化工作(3) (转)[@more@]

 

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

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

 }
  (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 SCOrlib.dll>
#include

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
//构造函数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="<}


  这是公共的测试文件:
//fmain.cpp
#include
#include "window.h"
void main()
{
 Window win2;
 std::cout<<"Test:win2: ";
 win2.Test();

  Window win(10,10,50,50);
 std::cout<<"Test:win: ";
 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
#include
//构造函数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:"< 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” : 没有合适的默认构造函数可用

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

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


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/10752019/viewspace-958280/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
  • 博文量
    3982
  • 访问量
    7895765