颗粒归收--构造函数与析构函数

一、构造函数与构析函数

作为比C更先进的语言,C#提供了更好的机制来增强程序的安全性。C#编译器具有严格的类型安全检查功能,它几乎能找出程序中所有的语法问题,这的确帮了程序员大忙。但是程序通过了编译检查并不代表错误已经不存在了,在“错误”的大家庭里,“语法错误”的地位只能算是冰山一角。级别高的错误通常隐藏的很深,不容易发现。

根据经验,不少难以察觉的错误是由于变量没有被正确初始化或清除造成的,而初始化和清除工作很容易被人遗忘。微软利用面向对象的概念在设计C#语言时充分考虑了这个问题并很好地予以解决:把对象初始化工作放在构造函数中,把清除工作放在析构函数中。当对象被创建时,构造函数被自动执行。当对象消亡时,析构函数被自动执行。这样就不用担心忘记对象的初始化和清除工作。

二、构造函数在C#中的应用

构造函数的名字不能随便起,必须让编译器认得出才可以被自动执行。它的命名方法既简单又合理:让构造函数与类同名。除了名字外,构造函数的另一个特别之处是没有返回值类型,这与返回值类型为void的函数不同。如果它有返回值类型,编译器将不知所措。在你可以访问一个类的方法、属性或其他任何东西之前,第一条执行的语句是包含有相应类的构造函数。甚至你自己不写一个构造函数,也会有一个缺省的构造函数提供给你。
下面列举了几种类型的构造函数
(1)缺省的构造函数
 //缺省的构造函数
    class TestClass
    {
        public TestClass() : base() { }
    }

(2)实例构造函数
实例构造函数是实现对类中实例进行初始化的方法成员。如:
//实例构造函数
    class Point
    {
        public double x, y;
        public Point()
        {
            this.x = 0;
            this.y = 0;
        }
        public Point(double x, double y)
        {
            this.x = x;
            this.y = y;
        }
        //。。。。。
    }

声明了一个类point,提供了两个构造函数。它们是重载的。一个是没有参数的point构造函数和一个是有两个double参数的point构造函数。如果类中灭有提供这个这些构造函数,那么CLR(公共语言运行库)会自动提供一个缺省构造函数的。但一旦类中提供了自定义的构造函数,如Point()和Point(double x,double y),则缺省构造函数将不会被提供,这一点要注意。
(3)静态构造函数
静态构造函数是实现对一个类进行初始化的方法成员。它一般用于对静态数据的初始化。静态构造函数不能有参数,不能有修饰符而且不能被调用,当类被加载时,类的静态构造函数自动被调用。如:

//静态构造函数
    class Employee
    {
        private static DataSet ds;
        static Employee()
        { 
            ds =new DataSet ("...");
        }
        //。。。。
    }
声明了一个有静态构造函数的类Employee。注意静态构造函数只能对静态数据成员进行初始化,而不能对非静态成员进行初始化。但是,非静态构造函数既可以对静态数据成员赋值,也可以对非静态数据成员进行初始化。
如果类仅包含静态成员,你可以创建一个private的构造函数:private TestClass() {…},但是private意味着从类的外面不可能访问该构造函数。所以,它不能被调用,且没有对象可以被该类定义实例化。

以上是几种类型构造函数的简单运用,下面将重点介绍一下在类的层次结构中(即继承结构中)基类和派生类的构造函数的使用方式。派生类对象的初始化由基类和派生类共同完成:基类的成员由基类的构造函数初始化,派生类的成员由派生类的构造函数初始化。

当创建派生类的对象时,系统将会调用基类的构造函数和派生类的构造函数,构造函数的执行次序是:先执行基类的构造函数,再执行派生类的构造函数。如果派生类又有对象成员,则,先执行基类的构造函数,再执行成员对象类的构造函数,最后执行派生类的构造函数。

至于执行基类的什么构造函数,缺省情况下是执行基类的无参构造函数,如果要执行基类的有参构造函数,则必须在派生类构造函数的成员初始化表中指出。

三、构造函数和垃圾回收器在C#中的运用

析构函数是实现销毁一个类的实例的方法成员。析构函数不能有参数,不能有任何修饰符而且不能被调用(是系统自动调用)。由于析构函数的目的与构造函数相反,就加前缀~以示区别。

虽然C#(更确切的说是CLR)提供了一种新的内存管理机制--自动内存管理机制,资源的释放是可以通过“垃圾回收器”自动完成的,但具体来说,仍有些需要注意的地方:
1、值类型和引用类型的引用其实是不需要什么“垃圾回收器”来释放内存的,因为当他们出了作用域后会自动释放所占内存,因为他们都保存在栈(Stack)中;

2、 只有引用类型的引用所指向的对象实例才保存在堆(Heap)中,而堆因为是一个自由存储空间,所以它并没有像"栈"那样有生存期("栈"的元素弹出后就代表生存期结束,也就代表释放了内存),并且要注意的是,"垃圾回收器"只对这块区域起作用;

然而,有些情况下,当需要释放非托管资源时,就必须通过写代码的方式来解决。通常是使用析构函数释放非托管资源,将用户自己编写的释放非托管资源的代码段放在析构函数中即可。需要注意的是,如果一个类中没有使用到非托管资源,那么一定不要定义析构函数,这是因为对象执行了析构函数,那么"垃圾回收器"在释放托管资源之前要先调用析构函数,然后第二次才真正释放托管资源,这样一来,两次删除动作的花销比一次大多的。下面使用一段代码来示析构函数是如何使用的:
  public class ResourceHolder
    {
        ~ResourceHolder()
        { 
            //这里是清理非托管资源的用户代码段
        }
    }

四.小结

1、当程序的执行离开实例化自动对象所在的作用域时,自动对象就会撤销,这时析构函数隐式调用,并不是说在main函数结束时才执行。
2、析构函数本身并不释放对象占用的内存空间,它只是在系统收回对象的内存空间之前进行扫尾工作,析构函数体内并不一定要有Delete语句。可以有也可以没有。
3、和构造函数一样,每个类都有一个析构函数,即使没有显式提供一个构析函数,编译器也会自动生成一个空的构析函数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值