C++(5) 构造函数、析构函数和封装案例

文章目录

      • 构造函数、析构函数和封装案例
        • 1. 构造函数和析构函数
          • 1.1 概述
          • 1.2 案例
          • 1.3 编译器自行提供构造函数
          • 1.4 拷贝构造函数和特殊用法
          • 1.5 构造函数总结和要求
        • 2. 封装案例
          • 2.1 封装的终极奥义
          • 2.2 封装一个 Cube 立方体

构造函数、析构函数和封装案例

1. 构造函数和析构函数
1.1 概述

构造函数用途

  • 首先配合 new 关键字使用
  • new 关键字根据构造函数名称对应的数据类型,在内存【堆区】申请必要的内存空间
  • 构造函数将对应的内存空间进行初始化赋值操作

格式和要求

  • 构造函数名称必须是【类名】
  • 构造函数没有返回值类型,也不需要使用 void 或者 void * 占位
  • 初始化操作列表根据当前实际所需完成
类名(必要的初始化参数列表)
{
	初始化语句;
}
1.2 案例
#include 

#include 
#include 
#include 

using namespace std;

class Person
{
public:
    /*
    当前函数就是一个构造函数,函数名对应当前的类名,函数的形式参数列表为空
    【无参数的构造函数】
    */
    Person()
    {
        // id 和 age 初始化
        id = 0;
        age = 0;

        // 构造函数,对 name 成员变量使用操作所需的内存空间进行申请和擦除
        name = (char *)malloc(32);
        memset(name, 0, 32);
        // name = "James";
    }

    // 有参数构造函数给予变量进行赋值操作
    Person(int id, char *name, int age)
    {
        this->id = id;
        this->age = age;

        this->name = (char *)malloc(32);
        memset(this->name, 0, 32);
        strcpy(this->name, name);
    }

    // 【拷贝构造函数】将参数 Person 对象数据内容,完整的拷贝一份给予当前实例化
    // Person 对象。当前参数是一个 Person & ,可以认为是用于初始化当前对象的数据载体
    // 将参数 Person 中的成员变量数据,赋值给新实例化对象
    Person(const Person & person)
    {
        // 将参数 person 中的数据内容,赋值给当前的新对象中
        id = person.id;
        age = person.age;

        name = (char *)calloc(1, 32);
        strcpy(name, person.name);
    }

    ~Person()
    {
        // delete 关键字销毁当前 new 创建的对象,会自动调用析构函数
        // 可以在析构函数中,释放成员变量或者其他操作申请的空间或资源

        // name 成员变量的数据内容时通过 malloc 申请的,需要通过 free 释放
        // 避免内存泄漏
        free(name);
    }

    void setId(int id) { this->id = id; }
    int getId() { return id; }
    
    void setName(char *name) { strcpy(this->name, name);}
    char * getName() { return name; }

    void setAge(int age) { this->age = age; }
    int getAge() { return age; }

private:
    int id;
    char *name;
    int age;
};

int main(int argc, char const *argv[])
{
    /*
    new Person; 没有明确任何参数,对应无参数构造参数
    new Person; // <==> new Person();
    */
    Person *p = new Person;

    cout << "ID : " << p->getId() << endl;
    cout << "Name : " << p->getName() << endl;
    cout << "Age : " << p->getAge() << endl;

    cout << "----------------------------------" << endl;

    /*
    利用实际参数,告知编译器,当前选择的构造函数时有参构造函数
    这里利用得时函数的【重载】
    */
    Person *p1 = new Person(3, "Wade", 32);

    cout << "ID : " << p1->getId() << endl;
    cout << "Name : " << p1->getName() << endl;
    cout << "Age : " << p1->getAge() << endl;
    cout << "---------------------------------" << endl;

    Person *p2 = new Person(*p1);

    cout << "p1 : " << p1 << endl;
    cout << "p2 : " << p2 << endl;

    cout << "ID : " << p2->getId() << endl;
    cout << "Name : " << p2->getName() << endl;
    cout << "Age : " << p2->getAge() << endl;

    /*
    class 类型,通过 delete 释放 new 申请的空间,
    会自动调用当前类中的析构函数 ~Person()

    delete 本是就是用于释放通过 new 申请的内存空间
    同时可以在析构函数中,释放/关闭其他必要的资源
    */
    delete p;
    delete p1;
    delete p2;

    return 0;
}

1.3 编译器自行提供构造函数
#include 

using namespace std;

/*
一个类没有【显式】定义构造函数,系统会自动给提供两个构造函数和默认析构函数
    1. 无参数构造函数
        【注意】如果代码中存在任何一个【显式】定义的构造函数,
        编译器不再提供默认无参数构造函数
    2. 拷贝构造函数:
        根据当前类中的成员变量数据情况,进行成员变量逐一拷贝赋值
    3. 默认析构函数

*/
class Person
{
public:
    int id;
    string name;
    int age;

    // Person(int id) { this->id = id; }
};

int main(int argc, char const *argv[])
{
    // 调用系统的无参数构造函数
    Person *p = new Person();

    p->id = 10;
    p->name = "Mary";
    p->age = 13;

    // 调用系统提供的默认拷贝构造函数
    Person *p1 = new Person(*p);

    cout << "ID : " << p1->id << endl;
    cout << "Name : " << p1->name << endl;
    cout << "Age : " << p1->age << endl;

    delete p;
    delete p1;
    
    return 0;
}
1.4 拷贝构造函数和特殊用法

同类型变量赋值操作,会调用拷贝函数完成对应代码

#include 

using namespace std;

class Person
{
public:
    int id;
    string name;
    int age;

    Person() {}

    Person(int id, string name, int age)
    {
        this->id = id;
        this->name = name;
        this->age = age;
    }

    // Person(int id) { this->id = id; }
    Person(const Person &person)
    {
        id = person.id;
        name = person.name;
        age = person.age;

        cout << "拷贝构造函数执行" << endl;
    }
};

int main(int argc, char const *argv[])
{
    Person p;

    p.id = 1;
    p.name = "张三";
    p.age = 17;

    /*
    发现代码中调用
        拷贝构造函数执行

    这里存在类重载 = 赋值号运算符的效果,将 p 数据赋值给 p1
    c++ 会自动调用拷贝构造函数,将 p 中的数据通过拷贝构造赋值
    给 p1 中的数据内容
    */
    Person p1 = p;

    cout << "ID : " << p1.id << endl;
    cout << "Name : " << p1.name << endl;
    cout << "Age : " << p1.age << endl;
    
    // 不同的地址
    cout << "p1 : " << &p1 << endl;
    cout << "p : " << &p << endl;
    
    return 0;
}
1.5 构造函数总结和要求
  • 任何一个定义类,必须提供无参数构造函数
  • 利用析构函数逻辑,一定要对当前对象使用的其他内存空间,或者必要的资源进行释放操作。
  • 拷贝构造函数是将参数对象的数据内容,赋值给当前对象,如果是在使用 = 赋值运算符,也会调用拷贝构造函数
2. 封装案例
2.1 封装的终极奥义
  • 一个代码如果使用三次以上,封装一个函数
  • 一组函数使用三次以上,封装一个工具
  • 一个工具开发中使用了三次以上,完成对应的完备的文档
2.2 封装一个 Cube 立方体
#include 

using namespace std;

class Cube
{
public:
    // 构造函数
    Cube() {}

    Cube(int length, int width, int height)
    {
        this->length = length;
        this->width = width;
        this->height = height;
    }
    Cube(const Cube & cube): length(cube.length), width(cube.width), height(cube.height) {}

    ~Cube() {}

    // 设置成员变量和成员变量数据相关函数
    void setLength(int length) { this->length = length; }
    int getLength() { return length; }

    void setWidth(int width) { this->width = width; }
    int getWidth() { return width; }

    void setHeight(int height) { this->height = height; }
    int getHeight() { return height; }

    // 体积获取
    int getVolume()
    {
        return length * width * height;
    }

    // 面积获取
    int getArea()
    {
        return 2 * (length * width + length * height + width * height);
    }

private:
    // 成员变量全部私有化,需要提供对应的 set 和 get 函数完成成员变量赋值和取值操作
    int length;
    int width;
    int height;
};

int main(int argc, char const *argv[])
{
    Cube * c1 = new Cube(10, 10, 10);

    cout << "Volume : " << c1->getVolume() << endl; // 1000
    cout << "Area : " << c1->getArea() << endl; // 600
    
    return 0;
}

你可能感兴趣的:(c++,开发语言,学习,学习方法,笔记)