C++学习4 | 构造函数constructor、析构函数destructor

我们先来看这样一段代码:

#include <iostream>
#include <string>
using namespace std;

class Point2D
{
public:
    void init(int x,int y);
    void paint();
private:
    int m_x;
    int m_y;
};

void Point2D::init(int x,int y)
{
    m_x=x;
    m_y=y;
}
void Point2D::paint()
{
    cout << m_x << "," << m_y << endl;
}
int main()
{
    Point2D p;
    p.init(1,2);
    p.paint();
    return 0;
}

在这段代码中,init函数是用来初始化对象p中的点的。

在C++中为了效率,在创建对象后编译器并不会为我们清理那个对象的空间。

举个例子:我们要搬进一个房子住,编译器不会帮我们清理那个房子,他觉得我们进入房子了以后会自己清理,这样的话清理两次影响效率。但是有些OOP语言会帮我们填充这个空间。在VS下,编译器会给这里填充一个16进制的0XCD,2个0XCD连起来就刚好是国标码中的“烫”。如果在一段程序中看到“烫烫烫烫”就说明碰到了未初始化的空间。

但是,调用init()完全靠程序员的自觉性。

在C++中提供了一个初始化的函数,称为constructor function。

/*构造函数,构造器,没有返回类型,必须和类的名字一样,会在对象被创建的时候自动被调用。*/

构造函数:

  • 为成员变量赋初始值,分配资源,设置对象的初始状态
  • 函数名与类名相同,没有返回类型
  • 对象创建时自动调用且只调用一次

              栈区创建对象:对象定义语句

              堆区创建对象:new操作符

  •  对象创建过程

              为整个对象分配内存

              构造基类部分(如果存在基类)

              构造成员变量

              执行构造函数代码

  •  一般访问属性为public,除非我们不允许外部创建对象
  • 构造函数重载

         构造函数通过参数表的差别形成重载

         不同的构造函数表示对象不同的创建方式,通过构造实参类型分配

         使用默认参数可以减少重载版本

  • 默认构造函数

         若一个类没有定义任何构造函数,那么编译器会提供一个公有的默认构造函数

         若定义了构造函数,编译器不会再提供默认构造函数

         默认构造函数一定是无参构造函数,无参构造不一定是默认构造函数

         默认构造函数作用

                  基本类型:不做初始化

                  类类型:调用对应类的缺省构造函数初始化对象

  • 初始化表

         在构造函数中使用初始化表,指明类的成员变量如何初始化

         类类型对象必须在初始化表中显示初始化,否则调用的是缺省构造函数来初始化

         常成员变量必须在初始化表中显示初始化

         参数初始化顺序与初始化表列出的变量的顺序无关,它只与成员变量在类中声明的顺序有关

/*没有参数的构造函数(编译器给的或者自己写的)叫做default constructor。构造函数有参数,析构函数没有参数。*/

析构函数:在对象被销毁的时候调用

 负责对象销毁时回收对象占用资源

 在析构函数中delete构造函数中new的东西

 在用完对象后 delete对象 调用析构函数 

class Teacher
{
private:
    string m_name,m_sex,m_subject;
    int m_age;
public:

//也可以给构造函数的参数赋默认值
//Teacher(string name="UNKNOW",int age=18,string sex="boy",string subject="C++")
//Teacher(string name,int age,string sex,string subject)
                :m_name(name),m_sex(sex),m_age(age),m_subject(subject)
// 下面是有参构造函数
    Teacher(string name,int age,string sex,string subject)
    {
        m_name = name;
        m_age = age;
        m_sex = sex;
        m_subject = subject;
        //如果成员变量为指针, *m_pAge
        //m_pAge = new int(age);    //开辟一个int堆空间,把形参age赋给堆空间
        //成员指针 m_pAge指向这个堆空间
    }
// 下面是无参构造函数
    Teacher()
    {
        m_name = "NULL";
        m_age = 0;
        m_sex = "UNKNOW";
        m_subject = "UNKNOW";
    }
// 下面这个是析构函数,如果在构造函数中new了,就要在析构函数中delete掉
    ~Teacher(){};
//下面是两个函数
    void teach()
    {
        cout << "teaching..." << endl;
    }
    void introduce()
    {
        cout << "I am " << m_name << "," << m_age << "," << m_sex << endl;
        cout << "I teach " << m_subject << endl;
    }
};

int main()
{
    Teacher* Mr_hanoi = new Teacher("hanoi",18,"boy","C++"); //new了一个对象,赋了值
    Mr_hanoi->introduce();  //调用这个对象的introduce函数
    delete Mr_hanoi; //删除对象
    
    Teacher Mis_li;
    Mis_li.introduce();
    delete Mis_li;
    return 0;
}

构造析构的顺序问题:

/*
 构造、析构顺序
 以下程序输出:
 A构造
 B构造
 C构造
 C析构
 B析构
 A析构
 */
#if 0
class A
{
public:
    A()
    {
        cout << "A构造" << endl;
    }
    ~A()
    {
        cout << "A析构" << endl;
    }
};
class B
{
public:
    B()
    {
        cout << "B构造" << endl;
    }
    ~B()
    {
        cout << "B析构" << endl;
    }
private:
    A a;
};
class C
{
public:
    C()
    {
        cout << "C构造" << endl;
    }
    ~C()
    {
        cout << "C析构" << endl;
    }
private:
    B b;
};

int main()
{
    C* pc = new C;
    delete pc;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Hanoi_ahoj/article/details/81415572