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

类别:编程语言 点击:0 评论:0 推荐:

 

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

    //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” : 没有合适的默认构造函数可用

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

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

本文地址:http://com.8s8s.com/it/it29240.htm