• 10.C++-构造函数初始化列表、类const成员、对象构造顺序、析构函数


    首先回忆下,以前学的const

    单独使用const修饰变量时,是定义的常量,比如:const int i=1;

    使用volatile const修饰变量时,定义的是只读变量

    使用const & 修饰变量时,定义的是只读变量

    在类中是否可以定义const成员?

    直接来写代码:

    #include <stdio.h>
    class Test
    {
    private:
      const int ci;
    public:
    //       Test()
    //       {
    //           ci=10;
    //       }
      int getCI()
      {
           return ci;
      }
    };
    int main()
    {
           Test t;
           printf("%d
    ",t.getCI());
           return 0;
    }

    编译出错:

    test.cpp: In function ‘int main()’:
    
    test.cpp:21: error: structure ‘t’ with uninitialized const members

    从编译信息看出,由于结构体t的const成员没有初始化,所以执行printf()出错.

    接下来取消上面示例的屏蔽,使用上章学习的构造函数来初始化const

    编译还是出错:

    test.cpp: In constructor ‘Test::Test()’:
    
    test.cpp:8: error: uninitialized member ‘Test::ci’ with ‘const’ type ‘const int’
    
    test.cpp:10: error: assignment of read-only data-member ‘Test::ci’

    从编译信息看出, Test::Test()构造函数里,不能直接初始化const变量.

    所以,在C++中,便引入了构造函数初始化列表除了可以给成员变量初始化,还可以对const成员初始化

    初始化列表位于构造函数名右侧,以一个冒号开始,接着便是需要初始化的变量,以逗号隔开,例如:

    class Example
    {
    private:
      int i;
      float j;
      const int ci;
      int *p;
    public:
       Test(): j(1.5),i(2),ci(10)    //初始化i=2,j=1.5,ci=10
      {
        p=new int;
        *p=3;
      }
    };

    注意:

    -列表成员的初始化顺序只与成员的声明顺序相同,与初始化列表的位置无关

    比如上个示例,初始化列表初始化的顺序为: i=2,j=1.5,ci=10

    -调用构造函数初始化时,会先执行初始化列表,再执行构造函数里的内容.

    那class类里的const成员是常量还是只读变量?

    参考以下示例:

    #include <stdio.h>
    
    class Test
    {
    private:
      const int ci;
    public:
          Test():ci(10)
          { }
      int getCI()
      {
           return ci;
      }
      void setCI(int val)
      {
         int *p=const_cast<int *>(&ci);
         *p=val;
      }
    };
    
    int main()
    {
        Test t;
        t.setCI(5);
        printf("%d
    ",t.getCI());
        return 0;
    }

    编译运行:

    5   

    所以class类里的const成员, 定义的是只读变量

    对象的构造顺序

    C++中的类可以定义多个对象,那么对象构造的顺序又是怎么样的?

    对于局部对象(栈)

    -程序执行到对象的定义语句时,便进行构造

    对于通过new创建的对象(堆)

    -和局部对象一样,程序执行到new语句时,便进行构造

    对于全局对象(静态存储区)

    -对象的构造顺序是不确定的,所以要尽量避免多个全局对象之间的相互依赖.

    对象的销毁-析构函数

    之前我们学习过创建对象时,有构造函数进行初始化.

    同样的,对象被销毁前也应该要有一些清理工作,所以,C++中引入了一个特殊的清理函数-析构函数

    •  析构函数的功能与构造函数相反,在对象被摧毁时自动调用
    •  析构函数没有参数,也没有返回值类型声明

    定义为: ~class_name(),例如:

    class Test{
    public:
       Test(){  }           //构造函数
       ~Test(){  }          //析构函数
    };

    注意:

    • 在类里,当定义了析构函数,编译器就不会提供默认的构造函数了,所以还要自己定义一个构造函数
    • 使用new创建的对象变量,在不使用时,需要使用delete,才能调用析构函数

    参考以下示例:

    #include <stdio.h>
    
    class Test
    {
      int val;
    
    public:
      Test(int i)
      {
        val=i;
        printf("Test() val=%d
    ",val); 
      }
      ~Test()
      {
          printf("~Test() val=%d
    ",val);
      }
    };
    
    int main()
    {
        Test t1(1);
        Test* t2 = new Test(2);
    
    //  delete t2;
        return 0;
    }

    编译运行:

    Test(1)
    Test(2)
    ~Test(1)

    从打印结果可以看出,t2的析构函数没有打印,所以只打印了:~Test(1)

    取消屏蔽后再次运行:

    Test(1)
    Test(2)
    ~Test(2)
    ~Test(1)

    总结:

    当类中有成员需要内存申请,文件打开,链接数据库等时,则需要定义析构函数,进行回收资源

    (和拷贝构造函数类似)

  • 相关阅读:
    PHP入门:在Windows中安装PHP工作环境
    Oracle数据库优化的经验总结
    引入js和css文件的总结
    PHP的加密解密字符串函数
    js+html5双人五子棋(源码下载)
    JAVA的网络编程基础概念
    asp.net的code-Behind技术
    10个调试Java的技巧
    Oracle基础 各种语句的定义格式
    CSS行高line-height的理解
  • 原文地址:https://www.cnblogs.com/lifexy/p/8584268.html
Copyright © 2020-2023  润新知