C++中的构造函数与析造函数详解

C++中的构造函数与析造函数详解

 构造函数的概念

(1)构造函数是特殊的成员函数
        (2)当创建类类型的新对象时,系统自动会调用构造函数
        (3) 构造函数是为了保证对象的每个数据成员都被正确的初始化。

        创建构造函数的注意事项:

(1) 函数名与类名相同;
        (2) 没有返回类型,返回类型也不能是void型
        (3) 构造函数通常情况下声明为public,否则不能像其它成员函数那样被显示的调用
        (4) 构造函数也可以声明为private,但是是用作特殊用途-----如单例类singleton时就是将构造函数声明为private.
        (5) 构造函数可以有任何类型与任意个数的参数,一个类可以定义多个构造函数(重载)

        关于默认构造函数:

默认构造函数是构造函数的其中一种。除此之外,还有拷贝构造函数与转换构造函数,这个后期再说明。默认构造函数是不带任何参数的构造函数,如果程序中未声明定义任何一个构造函数,则系统将自动产生一个默认的构造函数,此时不会对对象数据成员进行初始化,那么对象数据成员的值将是随机的。而如果我们提供了一个构造函数(只要是构造函数,无论是带参数的,还是不带参数的,是拷贝还是转换构造函数),哪怕只提供了仅仅一个构造函数,系统就不会再为我们提供默认构造函数了。

下面是关于构造函数的类定义:

class Test
{
public:
  Test(){} //系统不再提供默认构造函数
  Test(int val) //构造函数可以重载
  {
    val_ = val ;
  }
  ~Test(){} 

private:
  int val_;
};

下面代码是Test类的使用:

int main()
{
  Test t1; //系统调用不带参数的默认构造函数
  Test t2(5); //系统调用带一个参数的构造函数 

  Test *t3 = new Test(20); //分配内存+调用带一个参数的构造函数,这种操作称为new operator. 

  delete t3; // 调用析构函数+ 释放内存
}

请注意:全局对象的构造函数是先于main函数执行的

析构函数概念

(1) 函数名与类名类似,前面多了一个"~"符号(取反符)
        (2) 没有返回类型
        (3) 不能有参数
        (4) 不能被重载(这个好理解,因为没有参数,自然不能重载)
        (5) 如果没有定义析构函数,则编译器会自动生成一个默认的析构函数,函数体是空的。

 析构函数与对象数组

把握一个原则,构造几个对象,就要调用几次析构函数。

拿上面的Test类来进行举例说明:

int main()
{
  Test t[2] = {10,20}; //对象数组初始化,创建2个元素,即2个Test对象,分别传递初始值为10,20,就是说调用的是带一个参数的构造函数。由于创建了2个对象,构造函数也调用了两次
  Test *t2 = new Test(2); //仅创建一个对象,初始值为2,调用带一个参数的构造函数。 

  delete t2; //调用一次析构函数。 

  Test *t3 = new Test[2]; //在堆上创建2个对象,无初始值,调用的是不带参数的默认构造函数,由于是2个对象,故调用了2次。 

  delete [] t3; //调用两次析构函数,还有释放内存操作。
}

注意:析构函数可以被显式调用,但是当对象的生命周期结束后,系统还会再调用一次析构函数,这样就造成了调用2次析构函数,如果在析构函数中含有delete操作,就会出现问题。所以析构函数的显式调用比较少。STL源码中有用到析构函数的显式调用,这属于一些特殊用法。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • 详解C++中对构造函数和赋值运算符的复制和移动操作

    复制构造函数和复制赋值运算符 从 C++ 11 中开始,该语言支持两种类型的分配:复制赋值和移动赋值. 在本文中,"赋值"意味着复制赋值,除非有其他显式声明. 赋值操作和初始化操作都会导致对象被复制. 赋值:在将一个对象的值赋给另一个对象时,第一个对象将复制到第二个对象中. 因此, Point a, b; ... a = b; 导致 b 的值被复制到 a 中. 初始化:在以下情况下将进行初始化:声明新对象.参数通过值传递给函数或值通过值从函数返回. 您可以为类类型的对象定义"

  • 详解C++ 拷贝构造函数和赋值运算符

    本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义,但是也没有显式的删除),编译器会自动的隐式生成一个拷贝构造函数和赋值运算符.但用户可以使用delete来指定不生成拷贝构造函数和赋值运算符,这样的对象就不能通过值传递,也不能进行赋值运算. class Person { public: Person(const Person& p) = dele

  • 完全掌握C++编程中构造函数使用的超级学习教程

    构造函数是一种可初始化其类的实例的成员函数.构造函数具有与类相同的名称,没有返回值.构造函数可以具有任意数量的参数,类可以具有任意数量的重载构造函数.构造函数可以具有任何可访问性(公共.受保护或私有).如果未定义任何构造函数,则编译器会生成不采用任何参数的默认构造函数:可以通过将默认构造函数声明为已删除来重写此行为. 构造函数顺序 构造函数按此顺序执行工作: 按声明顺序调用基类和成员构造函数. 如果类派生自虚拟基类,则会将对象的虚拟基指针初始化. 如果类具有或继承了虚函数,则会将对象的虚函数指针

  • 详谈C++何时需要定义赋值/复制构造函数

    继承和动态内存分配 假设基类使用了动态内存分配,而且定义了析构函数.复制构造函数和赋值函数,但是在派生类中没有使用动态内存分配,那么在派生类中不需要显示定义析构函数.复制构造函数和赋值函数. 当基类和派生类采用动态内存分配时,派生类的析构函数.复制构造函数.赋值运算符都必须使用相应的基类方法来处理基类元素.这种要求是通过三种不同的方式来满足的.对于析构函数.这是自动完成的,也就是说在派生类的析构函数中无需显示调用基类的析构函数.对于构造函数,这是通过在初始化成员列表中调用基类的复制构造函数来完成

  • C++ 类的构造函数详解及实例

    C++ 类的构造函数 默认构造函数 如果你定义一个类,并且没有给它定义构造函数.编译器会为这个类提供默认的构造函数.如果你提供了构造函数,编译器是不会再为你提供一个默认构造函数的.编译器提供的默认构造函数什么都没做.类的成员变量将遵守默认的初始化规则. 编译器提供的默认构造函数的初始化规则: 在栈和堆中的类对象的内置或复合类型成员变量将为脏数据: 在全局变量区的类对象的内置或复合类型成员变量初始化为0: 类对象成员将调用默认的构造函数来初始化: #include <iostream> usin

  • C++详解默认参数的构造函数及简单实例代码

    现在给大家介绍下 有默认参数的构造函数: 大家知道函数获取形参的时候是通过函数调用时在实参里获得的,因此我们必须保证 实参的个数 和 形参的个数必须相同.而且有些情况下我们对于实参或许都是个固定的值.例如 我们需要计算长方形的面积 长x宽 但是用户可以不输入长 而且如果用户指定的情况下默认的长为 3,但是如果用户指定了则使用用户指定的宽 这就是用到默认参数了! 代码: #include <iostream> using namespace std; int area(int l,int w=3

  • C++中的构造函数与析造函数详解

    C++中的构造函数与析造函数详解  构造函数的概念 (1)构造函数是特殊的成员函数         (2)当创建类类型的新对象时,系统自动会调用构造函数         (3) 构造函数是为了保证对象的每个数据成员都被正确的初始化.         创建构造函数的注意事项: (1) 函数名与类名相同:         (2) 没有返回类型,返回类型也不能是void型         (3) 构造函数通常情况下声明为public,否则不能像其它成员函数那样被显示的调用         (4) 构造

  • C++分析构造函数与析造函数的特点梳理

    目录 构造函数的调用 构造函数的分类及调用 拷贝构造的调用时机 深拷贝与浅拷贝 构造函数的调用 默认情况下编译器至少给一个类添加3个函数 1.默认构造函数(无参,函数体实现)--完成对象的初始化 2.默认析构函数(无参,函数体为空)--完成对象的清理 3.默认拷贝构造函数,属性进行值拷贝 规则: 如果用户定义了有参构造,c++不会提供无参构造,但是提供默认拷贝构造 如果用户定义了拷贝构造函数,c++不会在提供其他函数 类名(){} 构造函数的语法 1,没有返回值,也不写void: 2,函数名称与

  • C++类中六个默认的成员函数详解

    浅谈 先来说一下"this指针": C++中通过引入this指针解决该问题,暨:C++编译器给每个"非静态的成员函数"增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问,只不过所有的操作对用户是透明的,暨用户不需要来传递,编译器自动完成. 说了这么多其实编译器在生成程序时获取对象首地址的信息.然后将获取的对象的首地址存放在了寄存器中,成员函数的其它参数都是存放在栈中.而this指针参数则是

  • pytorch中tensor.expand()和tensor.expand_as()函数详解

    tensor.expend()函数 >>> import torch >>> a=torch.tensor([[2],[3],[4]]) >>> print(a.size()) torch.Size([3, 1]) >>> a.expand(3,2) tensor([[2, 2], [3, 3], [4, 4]]) >>> a tensor([[2], [3], [4]]) 可以看出expand()函数括号里面为变形

  • php array_walk 对数组中的每个元素应用用户自定义函数详解

    php array_walk 对数组中的每个元素应用用户自定义函数 array_walk 使用用户自定义函数对数组中的每个元素做回调处理 基本语法 bool array_walk ( array &$array , callable $funcname [, mixed $userdata = NULL ] ) 将用户自定义函数 funcname 应用到 array 数组中的每个单元. array_walk() 不会受到 array 内部数组指针的影响. array_walk() 会遍历整个数组

  • Lua中编译执行代码相关的函数详解

    可以说Lua之所以称为是一种解释型的语言,正是因为有诸如load这样的函数,因为这样的函数使得Lua可以执行动态生成的代码.下面具体来分析这些函数. load函数 load函数原型如下: 复制代码 代码如下: load (chunk [, chunkname [, mode [, env]]]) 该函数加载一个chunk,如果没有错误,则返回一个函数.如果传入chunk的值是一个字符串,则就加载这个字符串:如果传入chunk的值是一个函数,则这个函数必须返回一个字符串,并且load会一直调用这个

  • JS中如何实现Laravel的route函数详解

    大家应该都知道在Laravel的路由模块里,我们可以给每一个路由设定一个名字,比如: Route::get('/blog/{blog}', 'BlogController@show')->name('blog.show') 然后就可以通过 route('blog.show', ['blog' => 1]) 来获取到这个路由的访问地址,后端跳转可以用 return redirect()->route('blog.show', ['blog' => 1]); 这样做的好处是如果发生ur

  • javascript中Array()数组函数详解

    在程序语言中数组的重要性不言而喻,JavaScript中数组也是最常使用的对象之一,数组是值的有序集合,由于弱类型的原因,JavaScript中数组十分灵活.强大,不像是Java等强类型高级语言数组只能存放同一类型或其子类型元素,JavaScript在同一个数组中可以存放多种类型的元素,而且是长度也是可以动态调整的,可以随着数据增加或减少自动对数组长度做更改. Array()是一个用来构建数组的内建构造器函数.数组主要由如下三种创建方式: array = new Array() array =

  • 对python中的高效迭代器函数详解

    python中内置的库中有个itertools,可以满足我们在编程中绝大多数需要迭代的场合,当然也可以自己造轮子,但是有现成的好用的轮子不妨也学习一下,看哪个用的顺手~ 首先还是要先import一下: #import itertools from itertools import * #最好使用时用上面那个,不过下面的是为了演示比较 常用的,所以就直接全部导入了 一.无限迭代器: 由于这些都是无限迭代器,因此使用的时候都要设置终止条件,不然会一直运行下去,也就不是我们想要的结果了. 1.coun

  • Java 逻辑结构与方法函数详解刨析

    ⭐前言⭐ 本文主要介绍JavaSE的逻辑结构和方法. 对一门编程语言逻辑结构和方法的理解是站在C语言之上的,建议配套C语言版本的分析一起食用 链接直达:

随机推荐