首页 > 其他分享 >9.构造函数和析构函数

9.构造函数和析构函数

时间:2022-09-05 13:23:43浏览次数:65  
标签:初始化 调用 函数 对象 Test 和析构 构造函数

文章内容

  1. 构造函数和析构函数的由来?
  2. 构造函数和析构函数的基本语法
  3. C++编译器构造析构方案 PK 对象显示初始化方案
  4. 构造函数的分类以及调用
  5. 默认的构造函数
  6. 构造函数调用规则
  7. 构造函数和析构函数的总结

1.构造函数和析构函数的由来?

  类的数据成员不能在类的声明时候初始化,如何解决这个问题? 使用构造函数处理对对象的初始化。构造函数是一种特殊的成员函数,与其他函数不同,不需要用户调用它,而是创建对象的时候自动调用。析构函数是对象不再使用的时候,需要清理资源的时候调用。

2.构造函数和析构函数的基本语法

A.构造函数:

  • C++中的类需要定义与类名相同的特殊成员函数时,这种与类名相同的成员函数叫做构造函数;
  • 构造函数可以在定义的时候有参数;
  • 构造函数没有任何返回类型。
  • 构造函数的调用:一般情况下,C++编译器会自动的调用构造函数。特殊情况下,需要手工的调用构造函数。
class Maker
{
    public:
        //构造函数的作用是初始化成员变量,是编译器去调用的
        Maker()
        {
            a = 10;
            cout << "构造函数" << endl;
        }

        //析构函数,在对象销毁前,编译器调用析构函数
        ~Maker()
        {
            cout << "析构函数" << endl;
        }
    public:
        int a;
};

B.析构函数:

  • C++中的类可以定义一个特殊的成员函数清理对象,这个特殊的函数是析构函数;
  • 析构函数没有参数和没有任何返回类型;
  • 析构函数在对象销毁的时候自动调用;
  • 析构函数调用机制: C++编译器自动调用。
class Maker
{
    public:
        //构造函数的作用是初始化成员变量,是编译器去调用的
        Maker()
        {
            a = 10;
            cout << "构造函数" << endl;
        }

        //析构函数,在对象销毁前,编译器调用析构函数
        ~Maker()
        {
            cout << "析构函数" << endl;
        }
    public:
        int a;
};

3.C++编译器构造析构方案 PK 对象显示初始化方案

class Test
{
private:
    int x;
public:
    Test(int x)
    {
        this->x = x;
        cout << "对象被创建" << endl;
    }
    Test()
    {
        x = 0;
        cout << "对象被创建" << endl;
    }
    void init(int x)
    {
        this->x = x;
        cout << "对象被创建" << endl;
    }
    ~Test()
    {
        cout << "对象被释放" << endl;
    }
    int GetX()
    {
        return x;
    }
};

int main()
{
    //1.我们按照C++编译器提供的初始化对象和显示的初始化对象
    Test a(10);
    Test b;      //显示创建对象但是还是调用无参构造函数,之后显示调用了初始化函数
    b.init(10);

    //创建对象数组(使用构造函数)
    Test arr[3] = {Test(10),Test(),Test()};
    //创建对象数组 (使用显示的初始化函数)
    Test brr[3];   //创建了3个对象,默认值
    cout<<brr[0].GetX()<<endl;
    brr[0].init(10);
    cout<<brr[0].GetX()<<endl;
    return 0;
}
————————————————
版权声明:本文为CSDN博主「下忍」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wue1206/article/details/81137353

  根据上面的代码, 我们得出使用显示的初始化方案: a.必须为每个类提供一个public的init函数; b. 对象创建后必须立即调用init函数进行初始化。
优缺点分析:

A. init函数只是一个普通的函数,必须显示的调用;
B. 一旦由于失误的原因,对象没有初始化,那么结果也是不确定的。没有初始化的对象,其内部成员变量的值是不定的;
C. 不能完全解决问题。

4.构造函数的分类以及调用

A. 无参构造函数

class Test
{
  private:
       int x;
  public:
       Test()
       {
         this->x=10;
       }
}

无参构造函数的调用: Test a;

B. 有参构造函数

class Test
{
  private:
       int x;
  public:
       Test(int x)
       {
         this->x=x;
       }
}

有参数构造函数的调用时机:

  • Test a(10); 调用有参数构造函数
  • Test b=(2,3); 逗号表达式的值是最后一位,调用有参数构造函数
  • Test c=Test(2); 产生一个匿名对象,直接转化成c(只会调用一次有参数构造函数)

C. 拷贝构造函数: 使用对象a初始化对象b

class Test
{
   private:
          int x;
   public:
          Test(const Test& a)
          {
             this->x=a.x;
          }
}

拷贝构造函数的调用时机:

class Test
{
private:
    int x;
public:
    Test(int x)
    {
        this->x = x;
        cout << "对象被创建" << endl;
    }
    Test()
    {
        x = 0;
        cout << "对象被创建" << endl;
    }
    ~Test()
    {
        cout << "对象被释放" << endl;
    }
    Test(const Test& a)
    {
        this->x = a.x;
        cout << "对象被释放(拷贝构造函数)" << endl;
    }
};
————————————————
版权声明:本文为CSDN博主「下忍」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wue1206/article/details/81137353
  • 第一个场景: 用对象a初始化对象b:
Test a(10);
//调用的是拷贝构造函数
Test b = a;
  • 第二个场景: 用对象a初始化对象b
Test a(10);
//调用的是拷贝构造函数
Test b(a)

第一个场景和第二个场景是一样的,用一个对象初始化另一个对象。

  • 第三个场景: 实参初始化形参的时候,会调用拷贝构造函数
Test a(10);
    //实参初始化形参
    PrintF(a);
  • 第四个场景: 函数返回一个匿名对象
    我们分析第四个场景前,我们看看下面的这个全局函数:
//该函数返回的是谁?
Test p()
{
    Test c(4);
    return c;
}

根据输出结果表明:

函数返回的是一个匿名对象。我们现在可以知道第四个调用场景是函数返回一个匿名对象的时候,会调用拷贝构造函数。
我们接着分析下面的两种情况:(接收匿名对象),判断匿名对象的去和留
A. 匿名对象初始化另一个对象:

Test a=p(); 

输出结果:

表明使用匿名对象初始化一个对象的时候, 匿名对象直接转化成初始化的那个对象。
B. 匿名对象赋值时:

 Test b;
    //匿名对象赋值另一个对象
    b = p();

输出结果:

表明使用匿名对象赋值另一个对象的时候,匿名对象赋值以后就会被析构。
匿名对象去和留总结:
A. 匿名对象初始化另一个对象时,匿名对象直接变成有名的对象(初始化的那个对象);
B. 匿名对象赋值另一个对象时,匿名对象赋值成功会被析构。

5.默认的构造函数

两个特殊的构造函数:
a. 默认的无参数构造函数: 当类中没有定义构造函数时,编译器会提供一个无参数构造函数,并且函数体为空;
b. 默认的拷贝构造函数: 当类中没有定义拷贝构造函数时,编译器会提供一个默认的拷贝构造函数,简单的进行成员变量的值复制。

6.构造函数调用规则

A. 当类中没有定义一个构造函数的时候,C++编译器会提供默认的无参数构造函数和拷贝构造函数;
B. 当类中定义了拷贝构造函数,C++编译器不会提供无参数构造函数;
C. 当类中定义了任意的非拷贝构造函数,C++编译器不会提供默认的无参数构造函数;
D. 默认的拷贝构造函数只是进行成员变量的简单赋值;

7.构造函数和析构函数的总结

A. 构造函数时C++中用于初始化对象状态的特殊函数;
B. 构造函数在对象创建的时候自动调用;
C. 构造函数和普通成员函数都遵循重载原则;
D. 拷贝构造函数是对象正确初始化的重要保障;
E. 必要的时候必须手工的写拷贝构造函数。

标签:初始化,调用,函数,对象,Test,和析构,构造函数
From: https://www.cnblogs.com/codemagiciant/p/16657751.html

相关文章

  • JS实现异步的方法:回调函数callback、事件监听、setTimeout、Promise、生成器Generato
    所有异步任务都是在同步任务执行结束之后,从任务队列中依次取出执行。回调函数是异步操作最基本的方法,比如AJAX回调,回调函数的优点是简单、容易理解和实现,缺点是不利于代码......
  • 基于IDL用户函数的波段运算
    ENVI 提供对 IDL 程序的访问的功能,可以使用内置的IDL 函数或者用户自定义IDL函数。这些函数要求它们接受一个或多个图像阵列作为输入,并且输出一个与输入波段具有相同行......
  • 有理函数积分
           ......
  • 普通函数、构造函数和匿名函数,以及手写callback回调函数
    回调函数functionpublic(callback){console.log("公共函数被调用");if(typeof(callback)=="function"){console.log(typeof(callback));callback()}//try......
  • python 下载url函数
    importrequestsimportshutildefdownload_file(url,local_filename):""":paramurl:url连接:paramlocal_filename:下载后保存文件名字"""......
  • 关于反三角函数及其导数
    关于反三角函数及其导数三角函数和反三角函数,在几何意义上,是x和y互换。三角函数里面,自变量x是角度,y是三角函数对x的运算结果。反三角函数里面,自变量x是针对某个角度y做......
  • 【JS每日一题】Array.reduce函数
    题目题目来源于前端面试题宝典[[0,1],[2,3]].reduce((acc,cur)=>{returnacc.concat(cur)},[1,2])解析[1,2]会作为初始值首次放入到第一个参数......
  • vue3——hook函数
    什么是hook?——本质是一个函数,把setup函数中使用的CompositionAPI进行了封装。类似于vue2.x中的mixin。自定义hook的优势:复用代码,让setup中的逻辑更清楚易懂......
  • postgresql/lightdb CommandCounterIncrement()函数的作用
    CommandCounterIncrement的作用是使当前事务中前面语句的修改对本语句可见,相当于oracle中的当前读概念(currentread,只不过oracle区分,pg不区分)。事务中每执行一个语句后......
  • 生命周期函数(面试)
    生命周期函数 beforeCreate()created()beforeMount()Mounted()beforeUpdate()Updated()beforeDestroy()destroyed()//......