精华内容
下载资源
问答
  • 构造函数与析构函数

    2013-01-24 13:29:25
    有关构造函数 与析构函数的详细讲解 里面也带有英文意思的解释 很不错!
  • 主要介绍了PHP构造函数与析构函数用法,简单讲述php中构造函数与析构函数的定义与使用方法,并结合实例形式演示了构造函数与析构函数的执行顺序,需要的朋友可以参考下
  • 本文章向大家介绍php构造函数与析构函数。 php构造函数 1.是对象创建完成后,“第一个”“自动调用”的方法 2.构造方法的定义,方法名是一个固定的, 在php4中:和类名相同的方法就是构造方法 在php5中:构造方法...
  • C++面向对象的编程入门篇--类构造函数与析构函数C++面向对象的编程入门篇--类构造函数与析构函数
  • C++ 语言一直被批评太复杂了,很多细节的地方需要仔细推敲,甚至其构造函数和析构的调用顺序也成为了一个让人迷惑的问题,在此我做了...这篇文章主要介绍了C++中构造函数与析构函数的调用顺序,需要的朋友可以参考借鉴。
  • 实验_构造函数与析构函数.doc实验_构造函数与析构函数.doc实验_构造函数与析构函数.doc
  • 构造函数与析构函数执行顺序
    构造函数与析构函数执行顺序
    代码:
    #include <iostream>
    using namespace std;
    
    class ABCD
    {
    public:
        ABCD(int a,int b,int c)
        {
            this->a = a;
            this->b = b;
            this->c = c;
            cout<<"ABCD的有参构造函数:"<<"a:"<<a<<" b:"<<b<<" c:"<<c<<endl;
        }
        
        ABCD(const ABCD& obj)
        {
            this->a = obj.a;
            this->b = obj.b;
            this->c = obj.c;
            cout<<"ABCD的拷贝构造函数:"<<"a:"<<a<<" b:"<<b<<" c:"<<c<<endl;
        }
    
        ~ABCD()
        {
            cout<< "ABCD的析构函数。。。" <<endl;
        }
    
        int getA() 
        {
            return this->a;
        }
    private:
        int a;
        int b;
        int c;
    };
    
    class mye
    {
    public:
        mye():a1(1,1,1),a2(2,2,2),m(100)
        {
            cout<<"mye的无参构造函数:"<<endl;
        }
    
        mye(const mye& obj):a1(1,1,1),a2(2,2,2),m(100)
        {
            cout<<"mye的拷贝构造函数:"<<endl;
        }
        ~mye()
        {
            cout<< "mye的析构函数。。。" <<endl;
        }
    public:
        ABCD& getA1()
        {
            return a1;
        }
    
    private:
        ABCD a1;
        ABCD a2;
        const int m;
    };
    
    int dothing(mye my1)
    {
        cout << "doThing() my1.a1.a:" << my1.getA1().getA() <<endl;
        return 0;
    }
    
    int run2()
    {
        mye mye1;
        dothing(mye1);
        return 0;
    }
    
    void main()
    {
       run2();
       system("pause");
    }

    执行结果:

    执行流程:

    main 函数调用 run2函数,在run2函数里,执行 mye mye1;
    即执行  mye(const mye& obj):a1(1,1,1),a2(2,2,2),m(100)这句话,
    先对 ABCD a1 和 ABCD a2 初始化,分别执行ABCD类的有参构造函数,
    打印出ABCD的有参构造函数:a:1 b:1 c:1
               ABCD的有参构造函数:a:2 b:2 c:2
    再去执行mye 类的无参构造函数,
    打印出mye的无参构造函数:
    执行 dothing(mye1)这句话,(mye1是个元素,进入 mye 类,调用 mye 类的拷贝构造函数),先对 ABCD a1 和 ABCD a2 初始化,分别执行ABCD类的有参构造函数,
    打印出ABCD的有参构造函数:a:1 b:1 c:1
               ABCD的有参构造函数:a:2 b:2 c:2
    再去执行mye 类的拷贝构造函数,
    打印出mye的拷贝构造函数:
    最后执行 dothing 函数输出的那句话,
    打印出doThing() my1.a1.a:1
    析构函数与构造函数执行的顺序相反
    打印出
               mye的析构函数。。。
              ABCD的析构函数。。。
              ABCD的析构函数。。。
              mye的析构函数。。。
              ABCD的析构函数。。。
              ABCD的析构函数。。。
    展开全文
  • c#构造函数与析构函数.doc
  • 我刚学C++构造函数与析构函数,现在自己写了一段代码,和你们分享
  • c++中关于构造函数与析构函数部分的课件,有助于初学者自学。
  • C++ 构造函数与析构函数

    千次阅读 2021-03-12 16:19:08
    C++ 构造函数与析构函数 构造函数的基本概念 构造函数: ​ 构造函数是类的一种特殊成员函数,它的名字和类名相同,可以有参数,但是没有返回值。类中定义的构造函数在对象生成时被调用,其作用是对对象初始化,进行...

    C++ 构造函数与析构函数

    构造函数的基本概念

    构造函数

    ​ 构造函数是类的一种特殊成员函数,它的名字和类名相同,可以有参数,但是没有返回值。类中定义的构造函数在对象生成时被调用,其作用是对对象初始化,进行成员变量赋值之类的操作。如果类中没有定义构造函数,编译器在编译过程中会为类生成一个默认的无参构造函数,并不进行任何操作。

    ​ 构造函数的意义:简化了对象的初始化工作,有了构造函数就不用专门再写初始化函数,也不用担心在生成对象时忘记调用初始化函数。对象名也相当于一个指针,如果没被初始化就使用将导致程序出错。

    class Complex{
        private:
        	double real;
        	double img;
        public:
        	// 一个类可以声明多个重载的构造函数,参数个数或参数类型不同
        	Complex(double r){real = r;}
        	Complex(double real_, double img_ = 0);
        	Complex(Complex c1, Complex c2);
    };
    
    Complex::Complex(double real_, double img_){
        real = real_;
        img = img_;
    }
    
    Complex::Complex(Complex c1, Complex c2){
        real = c1.real + c2.real;
        img = c1.img + c2.img;
    }
    
    int main(){
        Complex c1; // 这种声明方式是错误的,应为定义的构造函数为 Complex(r,i); 缺少构造函数参数
        Complex* pc = new Complex; // 也是错误的,没有参数
        Complex c2(2);
        Complex* pc2 = new Complex(2,3);
        return 0;
    }
    

    构造函数在数组中的使用

    class Sample{
        private:
        	int x;
        	int y;
        public:
        	Sample(){cout<<"Constructor 1 called"<<endl;}
        	Sample(int x_){x = x_; y = 0; cout<<"Constructor 2 called"<<endl;}
        	Sample(int x_, int y_){x = x_; y = y_; cout<<"Constructor 3 called"<<endl;}
    };
    
    int main(){
        Sample array1[2];
        cout<<"step1"<<endl;
        Sample array2[2] = {4,5};
        cout<<"step2"<<endl;
        Sample array3[2] = {3}; // array3[0]用Sample(3)初始化,array3[1]用Sample()初始化
        cout<<"step3"<<endl;
        Sample array4[3] = {3, Sample(4,5)};
        cout<<"step4"<<endl;
        Sample* array4 = new Sample[2];
        cout<<"step5"<<endl;
        Sample* parray[3] = {new Sample(3), new Sample(4,5)}; // 注意和第18行代码对比,parray是指针,没有进行初始化就是空指针不会调用构造函数
        delete [] parray;
        delete [] array4; // 被new出来的对象一定要用delete释放
        return 0;
    }
    /* output:
    Constructor 1 called
    Constructor 1 called
    step1
    Constructor 2 called
    Constructor 2 called
    step2
    Constructor 2 called
    Constructor 1 called
    step3
    Constructor 2 called
    Constructor 3 called
    Constructor 1 called
    step4
    Constructor 1 called
    Constructor 1 called
    step5
    Constructor 2 called
    Constructor 3 called
    */
    

    拷贝构造函数

    拷贝构造函数

    ​ 拷贝构造函数有且仅有一个同类对象引用的参数 (参数只能是引用不能是对象),形如 CClass:CClass(const CClass & c) 使用常量对象作为参数更安全,当然也可以不用 const。如果类中没有定义拷贝构造函数,编译器会在编译过程中为类生成默认的拷贝构造函数,其功能就是完成拷贝功能。
    如果拷贝构造函数中的参数不是一个引用,即形如 CClass(const CClass c) ,那么就相当于采用了传值的方式,而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构造函数。因此拷贝构造函数的参数必须是一个引用。需要澄清的是,传指针其实也是传值,如果上面的拷贝构造函数写成 CClass(const CClass* c),也是不行的。事实上,只有传引用不是传值外,其他所有的传递方式都是传值。

    class Complex{
        private:
        	double real;
        	double img;
        public:
        	Complex(int r, int i){real = r; img = i;}
        	Complex(const Complex & c);
    };
    
    Complex::Complex(const Complex & c){
        real = c.real;
        img = c.img;
        cout<<"Copy Constructor called"<<endl;
    }
    
    int main(){
        Complex c1(1,2);
        Complex c2(c1);
    }
    

    拷贝构造函数起作用的情况

    • 用对象进行初始化:当用一个对象去初始化同类的另一个对象时,会引发拷贝构造函数被调用。

      Complex c2(c1);
      Complex c2 = c1; //调用拷贝构造函数
      

      ​ 上述示例中的两条语句都会引发拷贝构造函数的调用,这两条语句是等价的,都用以初始化 c2。值得注意的是,第二条语句是初始化语句,不是赋值语句。赋值语句的等号左边通常是一个早已有定义的变量,赋值语句不会引发复制构造函数的调用,示例如下:

      Complex c1(1,2);
      Complex c2;
      c2 = c1; //赋值语句
      
    • 对象作为函数形参:如果函数 F 的一个参数是类 A 的对象,那么当 F 被调用时,类 A 的拷贝构造函数将被调用。换句话说,作为形参的对象是用拷贝构造函数初始化的,而且调用拷贝构造函数对其进行初始化的参数就是调用函数时所给的实参。

    • 对象作为函数返回值:如果函数的返冋值是类 A 的对象,则函数返冋时,类 A 的拷贝构造函数被调用。换言之,作为函数返回值的对象是用拷贝构造函数初始化的,而调用拷贝构造函数时的实参,就是 return 语句所返回的对象。

      class A{
          public:
          	int x;
          	A(int n){x=n;}
          	A(const A & a){
                  x = a.x; // 这个语句说明,拷贝构造函数的实参和形参的值不一定一样,这取决于该类的拷贝构造函数的定义方式(x = 100;)
                  cout<<"Copy construct called"<<endl;
              }
      };
      
      void F(A a){ // a做为形参,通过拷贝构造函数进行初始化
          cout<<a.x<<endl;
      }
      // 对象形参常引用参数的使用:优点在于减少了生成形参对象是调用拷贝构造函数的开销,如果需要保证实参的值不被改变加上 const
      void F(const A & a){
          cout<<a.x<<endl;
      }
      
      A Func(){
          A b(2);
          return b; // b作为返回值,通过拷贝构造函数进行初始化
      }
      
      int main(){
          A a1(1);
          F(a1); // a1作为拷贝构造函数的实参
          cout << Func().v << endl;
          return 0;
      }
      

    深拷贝和浅拷贝

    • 浅拷贝:又称值拷贝,将源对象的值拷贝到目标对象中去,本质上来说源对象和目标对象共用一份实体,只是所引用的变量名不同,地址其实还是相同的。(问题:浅拷贝和对象引用的区别是什么?)
    • 深拷贝:深拷贝的时候先开辟出和源对象大小一样的空间,然后将源对象里的内容拷贝到目标对象中去,这样两个指针就指向了不同的内存位置。
    • 深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。

    类型转换构造函数

    类型转换构造函数:用途在于自动将其他类型的数据对象转换为该类对象。类型转化构造函数和拷贝构造函数类似,只有一个参数,但是其参数不是该类对象。在需要的时候,编译系统在编译过程中自动调用转换构造函数,建立一个无名的临时对象。

    class Complex(){
        private:
        	double real,img;
        public:
        	Complex(double r, double i){
                real = r;
                img = i;
            }
        	Complex(int n){
                real = n;
                img = 0;
                cout << "Int Constructor called"<<endl;
            }
        	getReal(){return real;}
        	getImg(){return img;}
    };
    
    int main(){
        Complex c1(1,2);
        c1 = 3; // 调用类型构造函数,将3转换一个临时Complex对象
        cout << c1.getReal() << c1.getImg() << endl;
        return 0;
    }
    /* output:
    3 0
    */
    

    析构函数

    析构函数

    ​ 析构函数与构造函数对应,在对象生命周期结束时被自动调用,析构函数的作用是在对象消亡前做类似释放内存空间等善后工作。其名字和类目相同,在前面加 ~ ,没有参数和返回值,一个类最多只有一个析构函数。如果类中没有定义析构函数,编译器在编译过程中会生成缺省析构函数,并不进行任何操作。

    class String{
        private:
        	char* p;
        public:
        	String(){
                p = new char[10]; // new 申请动态内存空间
            }
        	~String();
    };
    String::~String(){
        delete [] p; // delete 释放动态内存空间
    }
    

    析构函数在数组中的使用:对象数组生命周期结束时,对象数组中的每个元素的析构函数都会被调用。

    析构函数与 delete :被 new 出来的对象一定要用 delete 释放,否则不会调用析构函数去释放对象;如果 new 的是一个对象数组,那么使用 delete [] 释放,如果只使用 delete ,那么只会调用一次析构函数释放一个对象。

    构造函数和析构函数的调用时机:值得注意的是,对象作为函数形参和返回值均会调用拷贝构造函数产生临时对象,那么这些对象在函数调用完成之后会自动调用析构函数释放资源。

    class Sample{
        private:
        	int x;
        public:
        	Sample(int n){x=n; cout<<x<<"constructor called"<<endl;}
        	~Sample(){cout<<x<<"destructor called"<<endl;}
    };
    
    Sample s1(1); // 全局变量,调用构造函数 
    
    void F(){
        static Sample s2(2); // 静态局部变量在函数调用结束时不会消亡,整个程序执行完毕之和才会消亡
        Sample s3(3);
        cout << "F called" << endl;
    }
    
    int main(){
        Sample s4(4); 
        s4 = 6; // 类型转换构造函数参数临时对象 
        cout<<"main"<<endl;
        if(true){
            Sample s5(5); // 局部变量在生命周期结束后调用析构
        }
        F();
        cout<<"main end"<<endl;
        return 0;
    }
    
    /* output:
    1 constructor called
    4 constructor called
    6 constructor called
    6 destructor called
    main
    5 constructor called
    5 destructor called
    2 constructor called
    3 constructor called
    F called
    3 destructor called
    main end
    6 destructor called (s4)
    2 destructor called (static)
    1 destructor called (global)
    */
    

    ​ 值得注意的是,构造函数只负责初始化工作不负责内存空间分配,析构函数不负责内存空间回收;将对象比作房子,入住之前调用构造函数进行装修,拆迁之前调用析构函数搬东西

    Reference

    拷贝构造函数详解

    深拷贝于浅拷贝

    展开全文
  • 对c#函数方法,构造函数与析构函数浅显的解释,让这些变得容易起来。
  • 主要讲解构造函数与析构函数的调用顺序,比较适合新人
  • 构造函数用来构造一个对象,主要完成一些初始化工作,如果类中不提供构造函数,编译器会默认的提供一个默认构造函数(参数为空的构造函数就是默认...析构函数是隐式调用的,delete对象时候会自动调用完成对象的清理工作
  • C++实验四——构造函数与析构函数 (1) 定义一个正方形类,该类包括:正方形的边长(取值范围为1-30个“*”),四个成员函数,分别为:取边长、设置边长、画正方形和在构造这些类对象时能初始化正方形边长。 编写主函数...
  • 构造函数与析构函数调用顺序

    构造函数

    • 构造函数不能有返回值
    • 缺省构造函数时,系统将会自动调用缺省构造函数初始化对象,缺省构造函数会将所有数据成员都初始化为零或者为空。
    • 创建一个对象时,系统自动调用构造函数。

    析构函数

    • 析构函数没有参数也没有返回值不能重载,也就是说,一个类中只能定义一个析构函数。
    • 如果一个类中没有定义析构函数,系统也会自动生成一个默认的析构函数,为空函数,什么都不做。
    • 调用条件:1,在函数体内定义的对象,当函数执行结束时,该对象所在类的析构函数会被自动调用;2,用new运算符动态构建的对象,在使用delete运算符时释放掉它。

    拷贝构造函数

    拷贝构造函数实际上也是构造函数,具有一般构造函数的所有特性,其名字也与所属类名相同。拷贝构造函数中只有一个参数,这个参数是某个同类对象的引用。它在三种情况下被调用:

    • 用类的一个已知的对象去初始化该类的另一个对象时;
    • 函数的形参是类的对象,调用函数进行形参和实参的结合时;
    • 函数的返回值是类的对象,函数执行完返回调用者。

    构造函数与析构函数的调用顺序

    对象是由“底层向上”开始构造的,当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,以此类推,直至达到派生类次数最多的派生次数最多的类的构造函数为止。
    因此,构造函数一开始构造时,总是要调用的它的基类的构造函数,然后才开始执行其他构造函数体,调用直接基类构造函数时,如果无专门说明,就调用直接基类的默认构造函数。

    而在对象析构时,其顺序正好相反。

    参考资料:
    构造函数与析构函数的调用顺序

    展开全文
  • 数据结构 C++ 详细注释 构造函数与析构函数 类型转换.rar
  • (四)C#之构造函数与析构函数

    千次阅读 2017-01-02 14:32:52
    构造函数与析构函数构造函数首先我们看一下实例构造函数的形式 |构造函数修饰符| 标识符 (|参数列表|) |: base(|参数列表|)| |:this(|参数列表|)| { 构造函数语句块; } 如果你以前没学过C++的构造函数或者第...

    构造函数与析构函数


    构造函数

    首先我们看一下实例构造函数的形式

    |构造函数修饰符| 标识符 (|参数列表|) |: base(|参数列表|)| |:this(|参数列表|)|
    {
    构造函数语句块;
    }

    如果你以前没学过C++的构造函数或者第一次看见写的这么乱七八糟的构造函数,我觉得你应该会骂人。
    那么下面就家几条注解吧:

    • 构造函数的修饰符号:这不就是我们熟悉的 public,private,protected这三个嘛。在C#中 internal 也是可以被当做修饰符的,这里便不再展开介绍修饰符的具体的访问规则。
    • 标识符不就是类名嘛,参数列表也不用多说。
    • :base:这个表示调用直接基类中的实例构造函数(就是调用它爸爸的构造函数呗)。
    • :this:调用该类本身所声明的其他构造函数(一个类可以有多个构造函数啊,因为类是可以被重载的嘛!所以就在这个构造函数里面调用了一下其他的构造函数呗)。
      怎么样?通过上面的分析你应该基本了解一个实例构造函数是怎样组成的了吧?如果还不是很清楚的话,我们看一下下面的一个小程序吧:
        public class Base {
            public Base() {
                Console.WriteLine("爸爸的构造函数被调用啦~");
            }
        }
        public class A :Base
        {
            public A() : this("hello"){
                Console.WriteLine("我是可以调用基类和我的其他构造函数的类");
            }
            public A(string info) : base()
            {
                Console.WriteLine("我是被其他构造函数调用的,它发过来字符串"+info);
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                A a = new A();
                Console.ReadLine();
            }
        }

    我们先猜测一下这个小例子会输出什么吧:

    • 首先调用构造函数A()
    • 然后呢,因为A()使用了this关键字,所以在还没有进入函数体的是否就调用了this("hello")也就是A(string info)
    • 这时候A(string info)构造函数被调用,但是由于该构造函数使用了base关键字,所以在没有进入函数体就去调用它爸爸构造函数Base()
    • 然后调用完Base()就依次的输出结果咯,整个过程其实就是一个压栈然后取栈顶元素的过程

    经过上面的分析,我们大致可以得到输出结果为

    爸爸的构造函数被调用啦~
    我是被其他构造函数调用的,它发过来字符串hello
    我是可以调用基类和我的其他构造函数的类

    对于实例构造函数我们补充说明一下几点:

    • 尽量不要用 base 和 this 关键字
    • 不能同时将this和base作用在同一个构造函数上。
    • 对于没有声明构造的类,系统会提供一个默认的构造函数。

    接下来我们看一下C#对于类中的字段的初始化!
    我们看一下下面的小程序:

        public class A
        {
            public A() {
                Console.WriteLine("A.A()");
            }
            private static int InitX()
            {
                Console.WriteLine("A.InitX()");
                return 1;
            }
            private static int InitY()
            {
                Console.WriteLine("A.InitY()");
                return 2;
            }
            private static int InitA()
            {
                Console.WriteLine("A.InitA()");
                return 3;
            }
            private static int InitB()
            {
                Console.WriteLine("A.InitB()");
                return 4;
            }
            private int y = InitY();
            private int x = InitX();
            private static int a = InitA();
            private static int b = InitB();
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                A a = new A();
                Console.ReadLine();
            }
        }

    输出结果如下:

    A.InitA()
    A.InitB()
    A.InitY()
    A.InitX()
    A.A()

    可以看出程序是先初始化类中的静态字段,再初始化非静态字段。且初始化的顺序与其排列的顺序呈现正相关。而构造函数是最后初始化的!
    根据上面说的原则,我们看一看下面的程序并预测一下输出结果:

        class Base
        {
            public Base(int x)
            {
                Console.WriteLine("Base.Base(int)");//4
                this.x = x;
            }
            private static int InitX()
            {
                Console.WriteLine("Base.InitX()"); //3
                return 1;
            }
            public int x = InitX();
        }
        class Derived : Base
        {
            public Derived(int a)
                : base(a)
            {
                Console.WriteLine("Derived.Derived(int)"); //5
                this.a = a;
            }
            public Derived(int a, int b)
                : this(a)
            {
                Console.WriteLine("Derived.Derived(int,int)"); //6        
                this.b = b;
            }
            private static int InitA()
            {
                Console.WriteLine("Derived.InitA()");//1
                return 3;
            }
            private static int InitB()
            {
                Console.WriteLine("Derived.InitB()");//2
                return 4;
            }
            public int a = InitA();
            public int b = InitB();
        }
        class Program
        {
            static void Main(string[] args)
            {
                Derived b = new Derived(1, 2);
                Console.ReadLine();
            }
        }
    • 调用Derived b = new Derived(1, 2);
    • 初始化Derived的静态方法:
      即:调用public int a = InitA();这时候输出Derived.InitA()
      再调用public int b = InitB();输出Derived.InitB()
    • 初始化构造函数,因为传过去的是两个参数,所以调用public Derived(int a, int b): this(a)
    • 因为该构造函数有this关键字,所以这时候调用public Derived(int a): base(a)
    • 因为这个构造函数有base关键子,所以调用其父类方法
    • 这时候初始化其父类,先初始化其静态变量再初始化非静态变量
      即:调用public int x = InitX();,这时候输出:Base.InitX()
    • 非静态变量出事完成,调用构造方法public Base(int x)输出:Base.Base(int)
    • 接着进入public Derived(int a): base(a)的方法体,输出:Derived.Derived(int)
    • 再接着进入public Derived(int a, int b): this(a)的方法体,输出:Derived.Derived(int,int)

    至此,我们分析完毕,我运行一下程序验证一下结果:
    运行结果1

    最后我们来看一下静态构造函数
    首先从其形式说起:

    [静态构造函数修饰符] 标识符(){/*静态构造函数的函数体*/}

    这时候按照惯例补充几点说明:

    • 静态函数修饰符,说的那么高大上,其实就是 static 关键字啦!
    • 静态构造函数只能对静态数据成员进行初始化(实例构造函数是都可以哦~)!
    • 如果没有写静态构造函数,而类中包含带有初始值设定的静态成员,那么编译器会自动生成默认的静态构造函数。
    • 静态构造函数是属于类的,不是属于实例的!所以说只会在类创建任何实例或者引用其静态数据成员的时候被执行一次(注意是只会被执行一次哦)!
      看一下代码更直观:

      class A
      {
          public static int x;
          public static int y;
          static A()
          {
              Console.WriteLine("静态构造函数被调用(只会输出一次哦~)");
              x = 10; //1
              y = 20;
          }
      }
      
      class Test
      {
          static void Main()
          {
              Console.WriteLine(A.x);
              Console.WriteLine(A.y);
          }
      }

      这个程序中虽然我们调用的两次它的静态方法,但是也只会调用一次它的静态构造函数,输出结果:

      静态构造函数被调用(只会输出一次哦~)

      当然我们要是先实例化一下A类,把Main()函数改成一下形式:

          static void Main()
          {
              new A();
              Console.WriteLine(A.x);
              Console.WriteLine(A.y);
          }

      结果一样只会输出一次。

    说了这么多,我们分析一下下面的程序的输出,加深一下印象!

        class A
        {
            protected static int x;
            protected int y;
            static A()
            {
                x = 10; //1
            }
            public A(int a, int b) //3
            {
                x = a;
                y = b;
            }
            public void print()
            {
                Console.WriteLine("x={0},y={1}", x, y);
            }
        }
        class B : A
        {
            protected new static int x;
            private int z;
            public B(int a, int b, int c)
                : base(a, b)
            {
                z = c; //4
            }
            static B()
            {
                x = 20; //2
            }
            new public void print()
            {
                Console.WriteLine("x={0},y={1},z={2}", x, y, z);
            }
        }
        class Test
        {
            static void Main()
            {
                A a = new B(3, 4, 5);
                a.print();
                B b = (B)a;
                b.print();
            }
        }

    我们来依次对该代码进行分析:

    • 因为是A类的实例,所以先初始化A的静态构造函数再初始化B类的静态构造函数,这时候:[ A类中 x=10 ],[ B类中x=20 ]。
    • 调用Bpublic B(int a, int b, int c): base(a, b)构造函数。(a=3; b=4; c=5)
    • 因为该构造函数有base关键字,所以调用父类(A)的public A(int a, int b)构造函数。这时候:[A类中 x=a=3; y=b=4;]。
    • 父类构造函数调用完毕,进入本身=构造函数的函数体。这时候:[B类中z=5;]。
    • 所有构造方法调用完毕。
    • a.print();的输出结果为:x=3,y=4
    • b.print();的输出结果为:x=20,y=4,z=5
    • 至此,程序运行完毕。

    C#中的构造函数部分已经讲完了,下面看看析构函数吧!

    析构函数

    首先析构函数的基本形式如下:

    ~ 标识符(就是类名啦) { /* 析构函数体 */ }

    说明几点:

    • 析构函数不能有程序显示的调用,是由系统在释放对象之前调用。
    • 析构函数在C#中充当鸡肋的作用,因为C#有垃圾回收器清理资源。
    • 析构函数是在垃圾回收器回收对象的空间之前调用的,最终会调用 System.ObjectFinalize()方法。

    觉得析构函数也啥可说的,C#其实提供了 Dispose()Close()方法来回收内存,三者的区别就如下啦:
    区别

    总结

    这一篇博客你我们学习了C#的构造函数与析构函数:
    首先简单介绍构造函数的概念,
    然后介绍了构造函数中的字段的初始化,
    接着有说了下静态构造函数。并且每个点都有响应的小例子。
    最后简单的说了下析构函数,比较了它与Dispose()Close()方法的区别!

    展开全文
  • 解析c++构造函数与析构函数

    千次阅读 2017-02-28 17:29:42
    析构函数构造函数的定义定义:构造函数是一种特殊的成员函数,对对象进行初始化的函数。构造函数的特点 构造函数名字必须类名相同。 构造函数不具有任何类型,没有返回值。 在建立类的对象的时候,系统会自动调用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 146,143
精华内容 58,457
关键字:

构造函数与析构函数