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

2018-06-17 21:02:17来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

首先回忆下,以前学的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\n",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\n",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\n",val); 
  }
  ~Test()
  {
      printf("~Test() val=%d\n",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)

 

总结:

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

(和拷贝构造函数类似)

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:二、C++复数的实现

下一篇:wxsqlite3的加密模块单独编译