女娲造人----构造析构与对象的生死

原创 2001年10月16日 11:14:00

女娲造人<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

                                                ----构造析构与对象的生死

作者:HolyFire

 

在《由始至终----构造与析构》最后我提到了C++中的构造函数和析构函数与对象的生和死有着很大的关系,好好运用还能控制对象的生死,使得编程的思路更接近现实世界的规律。

 

我们先回忆一下,在对象创建的时候,合适的构造函数将被自动调用,而对象销毁的时候,析构函数将被自动调用。在构造函数与析构函数可以被随意调用的情况下,也就是被声明为public的时候,这没有任何问题,但是一旦我们将他们的可视性改为privateprotected呢,那么情况就有所改观了。

 

声明为private的时候,那么除了类本身可以调用外,还有用friend关键字赋予信任关系的对象(一般是类或者函数)可以访问。

 

#include <iostream>

 

using namespace std;

 

class A{

public:

        static A * CreateA( void )

                {

                cout << "Create a A instance By class A's Member Function" << endl;

                return new A;

                }

private:

        A(){ }

friend A * CreateA( void );

};

 

A * CreateA( void )

{

        cout << "Create a A instance By class A's friend Function" << endl;

        return new A;

}

 

void main()

{

        A * a1 = A::CreateA();

        A * a2 = CreateA();

 

        delete a1;

        delete a2;

 

        cin.get();

}

 

结果是:

Create a A instance By class A's Member Function

Create a A instance By class A's friend Function

 

如果你直接用A a这样的方式,是无法创建A的实例的,编译器会告诉你,它帮不上忙。

 

当然,将析构函数声明为私有也可以限制将A的实例销毁的条件,那么

        delete a1;

        delete a2;

也会遭到编译器的抗议,我们需要另外写一个函数或者类来销毁他们。

 

在现实生活中有很多事物是有限的。比如说太阳系中只有一个太阳,如果有两个太阳会出什么乱子呢,真的是难以想象。在创建的对象有条件限制的时候,我们可以写文档告诉别人在编程的时候注意,但是随着工程的日益庞大,不要说别人,连自己也有可能忘记,在对条件限制要求非常严格的情况下,我们的知识便派上了用场。

 

结合刚才讲的将构造函数声明为私有的内容和《独一无二----静态成员变量》的内容,我们可以设计一个只能有一个实例的类型。下面是C++的源代码,这个例子中,对实例的销毁也加上了限制。

 

#include <iostream>

 

using namespace std;

 

class A{

private:

        static A * a;    //一个静态成员变量,类的所有实例所共有的

        A(){ cout << "This is class A , I couldn't direct Creat instance" << endl; }

        ~A(){ cout << "This is Class A , I coudn't direct Destroy instance" << endl; }

public:

        void ShowInstance(){ cout << this << endl; }

friend A * CreatObjectOfA( void );             //委托信任关系,由于类没有提供创建实例的方法,那么这个任务就交给了这个函数了。

friend void DestroyObjectOfA( A * a );             //对应创建,这个函数负责销毁产生的实例

};

 

A* A::a = NULL;

 

A * CreatObjectOfA( void )

{

        if( A::a == NULL )       //之前有没有创建过A的实例

                {//没有

                A::a = new A;

                cout << "This is a Class A Instance Creat By CreatObjectOfA Function ." << endl;

                }//创建过的话就不用再创建了

        return A::a;     //由于A::a是静态成员变量,那么返回的都是同一个指针

}

 

void DestroyObjectOfA( A * _a )

{

        if( A::a != NULL )//对应创建,如果现在有实例被创建过,那么销毁它

                {

                delete A::a;

                A::a = NULL;

                cout << "This is a Class A Instance Destroy By DestroyObjectOfA Function ." << endl;

                }

        _a = NULL;

}

 

void main()

{

        A * a1 , * a2 , * a3;

        a1 = CreatObjectOfA();

        a2 = CreatObjectOfA();

        a3 = CreatObjectOfA();

        a1->ShowInstance();

        a2->ShowInstance();

        a3->ShowInstance();

        DestroyObjectOfA( a1 );

        DestroyObjectOfA( a2 );

        DestroyObjectOfA( a3 );

        cin.get();

}

 

结果是:

 

This is class A , I couldn't direct Creat instance

This is a Class A Instance Creat By CreatObjectOfA Function .

00864898       //指向的都是同一个地方

00864898

00864898

This is Class A , I coudn't direct Destroy instance

This is a Class A Instance Destroy By DestroyObjectOfA Function .

 

至始至终只有一个实例被创建和销毁了

无论你创建多少次,这个类的实例最多有一个,这正是我们想要的。只要你肯去想,有很多有趣的事物在等着你。

 

将构造函数与析构函数声明为protected(保护),那么我们的目的就是这个类将作为基类,而且这个基类不能直接实例化。为什么要这样做,事实上我们在理解事物和对大量事物进行抽象的时候,会有一些不完整的片断,他们单独的出现是不合适的。比如说一些简单加工后的半成品,甚至是现实中找不到例子的,他们的语义是残缺不全的。也有完全抽象化的,比如说:“人”,不具体到男人,女人,小孩,大人,就无法用现实的思想来考虑它。

 

那么就用一个C++的例子来实现一下,从而掌握它。

 

#include <iostream>

 

using namespace std;

 

class A{

protected:

       A(){ cout << "This is class A , I couldn't direct Creat instance" << endl;}

};

 

class B : public A{

public:

       B(){ cout << "This is class B public inherit From class A , I could Creat instance By class B" << endl; }

};

 

void main()

{

       B b;

       cin.get();

}

 

结果是:

This is class A , I couldn't direct Creat instance

This is class B public inherit From class A , I could Creat instance By class B

 

这个例子很简单,我们不需要花多少时间就能理解。

 

到现在才回到标题上来似乎有些突然,但是没有上面的解释,理解起来会有些困难,那么废话少说,我们直接切入主题。

 

中国古老的传说中,人是女娲用泥巴做的,所以说,人不能随意创建,可以创建人的事物可以是女娲。

女娲变出了男人和女人,女人可以生孩子,也就是可以创建人,但是只有男人才能让女人生孩子,所以关系是,要创建人必须要有一个男人来让一个女人生孩子,生孩子的行为是女人的,但是主动权也就是男人才有权利使用女人的行为,这是男人的行为。我们可以理解为男人的行为是发一条消息来告诉女人,女人采用相应的行为来处理。

 

我们来整理一下:(我使用一种简化的模式来考虑问题,要点在于理清构造函数对于对象生死的关系)

男人和女人都是人,女人可是生孩子,孩子也是人,所以孩子要分成男人和女人,那么女人生孩子事实上是两种行为,生男孩,生女孩,男人也有两种行为,让女人生男孩,让女人生女孩。

 

女娲{ 创造男人,创造女人 }

 

{}

 

男人{ ,让女人生男孩(男人) ,让女人生女孩(女人)}

女人{ ,生男孩(男人),生女孩(女人)}

 

class Person{   //

protected:

       Person(){}  //构造函数可以让派生类使用,也就是男人和女人使用

};

 

class Man;

class Woman;

 

class NvWa{      //女娲

public:

       Man * CreatAMan(void);      //创造男人

       Woman * CreatAWoman( void ); //创造女人

};

 

class Woman : virtual public Person{   //女人

private:

       Woman(){}

       Man * CreatAMan( void );          //生男孩(男人)

       Woman * CreatAWoman( void ); //生女孩(女人)

friend NvWa;

friend Man;

};

 

class Man:virtual public Person{  //男人

private:

       Man(){}

public:

       Man * GetABoy( Woman * woman )         //让女人生男孩(男人)

              {

              return woman->CreatAMan();

              }

       Woman * GetAGirl( Woman * woman )     //让女人生女孩(女人)

              {

              return woman->CreatAWoman();

              }

friend NvWa;

friend Woman;

};

 

Man * NvWa::CreatAMan( void )

{

       return new Man;

}

 

Woman * NvWa::CreatAWoman( void )

{

       return new Woman;

}

 

Man * Woman::CreatAMan( void )

{

       return new Man;

}

 

Woman * Woman::CreatAWoman( void )

{

       return new Woman;

}

 

void main()

{

       NvWa nvwa;  //女娲

 

       Man * man = nvwa.CreatAMan();                    //创造了一个男人

       Woman * woman = nvwa.CreatAWoman();       //创造了一个女人

 

       Man * boy = man->GetABoy( woman );    //男人让女人生了一个男孩

       Woman * girl = man->GetAGirl( woman ); //又让女人生了一个女孩

 

       delete man;

       delete woman;

       delete boy;

       delete girl;

 

}

 

其实细心的朋友不难发现,创建人可以抽象成一个行为,男人和女人都是人,但是这样做不知道生下来的是男孩或是女孩,因为继承的特性不能由其基类来得知派生类的信息,这个问题在C++中也有解决的办法,我会在以后的文章中介绍。

 

2001/9/18

丁宁 

从女娲造人,看JAVA中"类"的应用

从女娲造人,看JAVA中"类"的应用 从女娲造人,看JAVA中"类"的应用通过对本文的理解,你将掌握到以下知识点:类 构造函数 方法 方法的重载 对象 传参 返回值伟大的神女娲是一位神奇的人身蛇尾女神...
  • hz
  • hz
  • 2006年10月04日 17:32
  • 841

简单工厂模式--女娲造人造啥做啥

有这样一个问题,以面向对象的方法去实现一个简单的计算器该怎么实现呢? 首先,有种很简单的思路,输入两个数,然后判断运算符类型,进行相应运算,最后输出结果。 这样的方法虽然也能完成,但是不符合面向对象的...
  • anLA_
  • anLA_
  • 2017年07月26日 17:08
  • 659

设计模式--工厂方法模式【Factory Method Pattern】

声明:本文从网络书籍整理而来,并非原创。女娲造人(第一次尝试)女娲在补了天后,下到凡间一看,哇塞,风景太优美了,天空是湛蓝的,水是清澈的,空气是清新的,太美丽了,然后就待时间长了就有点寂寞了,没有动物...
  • sinat_20645961
  • sinat_20645961
  • 2015年09月16日 09:25
  • 1177

java设计模式 实验一-简单工厂模式

**简单工厂模式** 班级:软件工程1班 姓名:张雨 学号:2014416558 一、实验目的: 简单工厂设计模式应用 二、实验内容: 题目(一): 使用简单工厂模式模拟女娲(N...
  • a1120575649
  • a1120575649
  • 2016年09月23日 23:20
  • 780

包含对象成员的类的构造与析构顺序

构造函数的执行顺序: (1)存在继承关系时,先执行父类的构造函数,再执行子类的构造函数; (2)当一个类中含有对象成员时,在启动本类的构造函数之前,先分配对象空间,按对象成员的声明顺序执行他们各自的构...
  • pfd001
  • pfd001
  • 2016年03月25日 04:00
  • 994

Python高级特性:类构造与析构

本文主要结合一些实际的例子,介绍了Python类的构造,初始化和析构的原理。 参考资料 1. https://www.python.org/download/releases/...
  • u010096900
  • u010096900
  • 2015年03月23日 22:59
  • 1249

C++对象的构造函数和析构函数详解

 C++对象的构造函数和析构函数详解 你好,C++(33)对象生死两茫茫 6.2.3 一个对象的生与死:构造函数和析构函数 6.2.2  使用类创建对象 完成某个类的声明并且定义其成员函...
  • mynote
  • mynote
  • 2015年03月18日 12:23
  • 1103

先构造的一定后析构么,后构造的一定先析构么?

先构造的一定后析构么,后构造一定先析构么? 首先要看一个 /* 设已经有A,B,C,D 4个类的定义,程序中A,B,C,D 析构函数调用顺序 */ C c; void main () { ...
  • wretchedme
  • wretchedme
  • 2015年04月28日 10:24
  • 933

C++学习笔记之——局部对象和临时对象的构造和析构时机

在写这篇文章之前,一直没有注意过C++中临时对象何时调用析构的。直到最近看代码的过程中遇到这种情况。 由于不了解临时对象何时调用析构函数,所以很不了解代码的实现。甚至还用局部对象的析构时机去看待。先讲...
  • huangjh2017
  • huangjh2017
  • 2017年04月19日 17:22
  • 415

Qt编程--发现小知识点,析构Object类时,自动析构其子对象

在学习Qt时,发现,构造一个QObject对象A,并把另一个QObject对象B作为A的父对象传入,当析构对象A时,对象B也将被自动析构。 验证如下: mainWindow.h ...
  • humadivinity
  • humadivinity
  • 2016年04月21日 15:48
  • 1170
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:女娲造人----构造析构与对象的生死
举报原因:
原因补充:

(最多只允许输入30个字)