• 构造函数与析构函数一


    • 构造函数是特殊的成员函数。
    • 创建类类型的新对象,系统自动会调用构造函数。
    • 构造函数是为了保证对象的每个数据成员都被正确初始化。
    • 函数名和类名完全相同。
    • 不能定义构造函数的类型(返回类型),也不能使用void。
    • 通常情况下构造函数应声明为公有函数,否则它不能像其他成员函数那样被显式地调用。
    • 构造函数被声明为私有有特殊的用途。【单例模式的应用】
    • 构造函数可以有任意类型和任意个数的参数,一个类可以有多个构造函数(重载)。

    对于有编程经验的人来说上面的很容易理解,下面具体来看下构造函数在C++中的使用:

    Test.h:

    #ifndef _TEST_H_
    #define _TEST_H_
    
    class Test
    {
    public:
        Test();
    private:
        int num_;
    };
    #endif // _TEST_H_

    Test.cpp:

    #include "Test.h"
    #include <iostream>
    using namespace std;
    
    // 不带参数的构造函数称为默认构造函数
    Test::Test()
    {
        num_ = 0;
        cout<<"Initializing Default"<<endl;
    }

    下面来调查用测试下:

    01.cpp:

    #include "Test.h"
    
    int main(void) {
        Test t;
        return 0;
    }

    编译运行:

    如预其一样,调用了默认构造函数,其中构造函数是自动调用的,

    •  不带参数的构造函数,上面已经说明了。
    • 如果程序中未声明,则系统自动产生出一个默认构造函数。
      这时将我们声明的默认构造函数去掉:



      这时编译运行:

      这是由于没有对num成员变量进行人为初始化,所以它的值就是不确定的。
      如果类不提供任何一个构造函数,系统将为我们提供一个不带参数的默认的构造函数,而如果声明了带参数的构造函数,系统则不会为我们提供不带参数的默认构造函数了,如下:


      而这时如果还是调用默认构造函数,肯定会出错:


      这时调用构造时需要传递一个参数才行:

      编译运行:

     跟方法重载类似,很容易理解:

    编译运行:

     

    编译运行:

    •  函数名和类名相似(前面多了一个字符“~”)。
    • 没有返回类型。
    • 没有参数。
    • 析构函数不能被重载。
    • 如果没有定义析构函数,编译器会自动生成一个默认析构函数,其格式如下:

        类名::~默认析构函数名( )

        {

        }
    • 默认析构函数是一个空函数。

     

    编译运行看构造与析构顺序:

    从中可以发现,构构顺序是跟创建顺序相反的。

     

    编译运行:

    从运行结果来看,确实全局对象的构造是先于main函数的。 

     

    编译运行:

    从中是初始化了两个对象,调用了两次构造。 

    需要注意上面的两种形式代表的不同含义,编译运行:

     当调用delete运算符时,不但释放了内存,还调用了析构函数,具体如上面的输出结果既可以看出来。

    【一般很少这样做,只有在特珠的场合才这样做,之后遇到会来使用它】

    编译运行:

    上节中实现过一个时钟类,这里新建一个工程,将上次的时钟类导进来,基于这个来进行新语法的说明,先看一下之前编写的代码:

    Clock.h:

    //#pragma once
    #ifndef _CLOCK_H_
    #define _CLOCK_H_
    
    class Clock
    {
    public:
        void Display();
        void Init(int hour, int minute, int second);
        void Update();
    
        int GetHour();
        int GetMinute();
        int GetSecond();
    
        void SetHour(int hour);
        void SetMinute(int minute);
        void SetSecond(int second);
    private:
        int hour_;
        int minute_;
        int second_;
    };
    #endif // _CLOCK_H_

    Clock.cpp:

    #include "Clock.h"
    #include <iostream>
    using namespace std;
    
    void Clock::Display()
    {
        cout<<hour_<<":"<<minute_<<":"<<second_<<endl;
    }
    
    void Clock::Init(int hour, int minute, int second)
    {
        hour_ = hour;
        minute_ = minute;
        second_ = second;
    }
    
    void Clock::Update()
    {
        second_++;
        if (second_ == 60)
        {
            minute_++;
            second_ = 0;
        }
        if (minute_ == 60)
        {
            hour_++;
            minute_ = 0;
        }
        if (hour_ == 24)
        {
            hour_ = 0;
        }
    }
    
    int Clock::GetHour()
    {
        return hour_;
    }
    
    int Clock::GetMinute()
    {
        return minute_;
    }
    
    int Clock::GetSecond()
    {
        return second_;
    }
    
    void Clock::SetHour(int hour)
    {
        hour_ = hour;
    }
    
    void Clock::SetMinute(int minute)
    {
        minute_ = minute;
    }
    
    void Clock::SetSecond(int second)
    {
        second_ = second;
    }

    其测试代码如下:

    #include "Clock.h"
    
    int main(void)
    {
        Clock c;
        c.Init(10, 10, 10);
        c.Display();
        //c.second_ += 1;
        c.Update();
        c.Display();
    
        //c.hour_ = 11;
        c.SetHour(11);
        c.Display();
    
        return 0;
    }

    编译运行其结果是:

    首先第一步改造一下原有的代码,将数据成员的初始化放到构造函数中:

    接下来正式开始学习转换构造函数,先简单认识一下它:

    • 单个参数的构造函数
    • 将其它类型转换为类类型
    • 类的构造函数只有一个参数是非常危险的,因为编译器可以使用这种构造函数把参数的类型隐式转换为类类型【有办法限止这种转换,下面explicit会说明】

    也就是说,带一个参数的构造函数有以下两个功能:

    1、普通构造函数(只能进行初始化)

    2、转换构造函数(除了初始化之后,还能进行类型转化)

    下面用代码进行说明,还是延用上节中的Test类,如下:

    Test.h:

    #ifndef _TEST_H_
    #define _TEST_H_
    
    class Test
    {
    public:
        // 如果类不提供任何一个构造函数,系统将为我们提供一个不带参数的
        // 默认的构造函数
        Test();
        Test(int num);
        void Display();
    
        ~Test();
    private:
        int num_;
    };
    #endif // _TEST_H_

    Test.c:

    #include "Test.h"
    #include <iostream>
    using namespace std;
    
    // 不带参数的构造函数称为默认构造函数
    Test::Test()
    {
        num_ = 0;
        cout<<"Initializing Default"<<endl;
    }
    
    Test::Test(int num)
    {
        num_ = num;
        cout<<"Initializing "<<num_<<endl;
    }
    
    Test::~Test()
    {
        cout<<"Destroy "<<num_<<endl;
    }
    
    void Test::Display()
    {
        cout<<"num="<<num_<<endl;
    }

    编译运行看是否这时创建有两个对象了:

    为了更清楚的看到临时对象的生成,下面这样做:

    •  在初始化语句中的等号不是运算符。编译器对这种表示方法有特殊的解释
    • 赋值
    • Test& Test::operator=(const Test& other);
      关于运算符的重载,之后会仔细学习,这里先为了说明问题简单使用一下,上面是运算符重载的形式,下面重载=号运算符:


      编译运行:

      如果再赋值一个对象:

      运行结果如下:

      另外对于自己重写的等号运算符可以写得更加好一些,修改如下:

    •  只提供给类的构造函数使用的关键字。
    • 编译器不会把声明为explicit的构造函数用于隐式转换,它只能在程序代码中显示创建对象

  • 相关阅读:
    软件工程(2019)第一次作业
    Coding.net主页地址链接
    解决Oracle 11g重建em时报错创建档案资料库时出错以及删除原有em时报监听程序未启动
    解决VirtualBox与锐捷网络冲突的问题
    王道数据结构复习(一)
    第二次结对编程—四则运算自动生成程序
    软件工程(2019)结对编程第一次作业
    软件工程(2019)第三次个人作业——求最大子段和(于VS2017下代码覆盖单元测试)
    软件工程(2019)第二次作业
    软件工程第一次作业
  • 原文地址:https://www.cnblogs.com/webor2006/p/5049727.html
Copyright © 2020-2023  润新知