C++对象的生命周期

  1. 为对象创建内存
  2. 创建对象的各个成员变量(调用各个成员变量的构造函数)
  3. 调用构造函数初始化对象自身
  4. 使用对象...
  5. 调用析构函数释放对象使用的资源。
  6. 销毁各个程序员变量(调用各个成员变量的析构函数)
  7. 释放内存

析构函数 (Destructor)

作用:释放对象对象使用的资源。

析构函数 会在对象销毁前自动调用。如果类内没有定义析构函数,则编译器也会为其添加一个析构函数,默认的析构函数什么都不做。

析构函数的语法

class 类名{
    public:
    ~类名(void) {
        ... 做释放内存或关闭文件等操作。
    }
}

说明:

  • 析构函数只有一个,且不能重载。
  • 析构函数没有参数和返回值。
  • 析构函数会在对象销毁前自动调用。无需手动调用。

全局变量(对象)的构造和析构函数调用规则

全局变量(对象)存在于数据段,而数据段是在 main 函数调用之前创建,并创建数据段内的对象,因此全局变量(对象)的构造函数会先用main调用。同样析构函数也会在 main 函数结束后调用。

构造函数的传参语法

类名 对象名;  // 调用无参的构造函数
类名 对象名(实参列表);  // 调用有参的构造函数,根据重载规则匹配构造函数
类名 对象名 = 值;  // 调用一个参数的构造函数(同时根据重载匹配规则)

int i = 0;  //等同于 int i(0);

示例代码

#include <iostream>
#include <stdlib.h>
#include <string.h>

using namespace std;

// 定义一个MyString类,使用动态数组来存储字符信息
class MyString {
    public:
        // 将字符串初始化成 n个内容为 c的字符
        MyString(char c, int n) {
            cout << "MyString(" << c << "," << n<<")\n";
            data = (char*)malloc(n+1);
            for (int i = 0; i < n; i++) {
                data[i] = c;
            }
            data[n] = '\0';
        }
        MyString(const char * p=""):data(NULL) {
            cout << "MyString(" << p << ")\n";
            // 计算传入参数的长度
            int str_len = strlen(p);
            data = (char*)malloc(str_len+1);
            strcpy(data, p);
        }
        // 析构函数
        ~MyString(){
            cout << "~MyString(" << data << ")" << endl;
            free(data);
        }
    private:
        char * data;
};

int main(int argc, char * argv[]) {
    MyString s1;  // 调用无参数的构造函数
    MyString s2('x', 10);  // 根据重载规则调用两个参数的构造函数。
    MyString s3("name1"); // 调用一个参数的构造函数
    MyString s4 = "name2"; // 调用一个参数的构造函数

    cout << sizeof(s1) << endl;
    cout << "程序结束!" << endl;
    return 0;
}

// MyString x1("world");
// MyString x2("1111");

new 和 delete 关键字

作用:在堆上创建对象和释放对象 。

C 语言分配内存的方法: malloc/free

C++ 创建对象的方法: new / delete

  • new 分配内存,同时调用构造函数
  • delete 调用析构函数,然后释放内存

语法

// 创建单个对象
new 类名;  // 调用无参数的构造函数
new 类名(实参列表); // 根据重载规则调用有参数的构造函数

// 创建对象数组
new 类名[对象个数(整数)]
// 创建对象数组,并指定构造函数
new 类名[对象个数(整数)]{每个对象的初始化构造函数}

// 销毁单个对象
delete 对象地址
// 销毁对象数组
delete [] 对象地址

深拷贝和浅拷贝

浅拷贝:是指在复制对象的过程中,对象的每个成员都依次赋值给新对象的成员各个成员。

对象的默认复制是浅拷贝

深拷贝:是指在复制对象的过程中,每个对象的资源都各自独立,不共用,成为独立的个体。

拷贝构造函数(copy construtor)

作用:是进行深拷贝

语法格式

class 类名{
    类名(const 类名 & src){}
};

说明:

  • 拷贝构造数是C类的缺省构造函数。如果不写此构造函数。C 默认生成一个缺省的构造函数。默认执行浅拷贝

示例代码

#include <stdlib.h>
#include <string.h>

using namespace std;

// 定义一个MyString类,使用动态数组来存储字符信息
class MyString {
    public:
        // 将字符串初始化成 n个内容为 c的字符
        MyString(char c, int n) {
            cout << "MyString(" << c << "," << n<<")\n";
            data = (char*)malloc(n+1);
            for (int i = 0; i < n; i++) {
                data[i] = c;
            }
            data[n] = '\0';
        }
        MyString(const char * p=""):data(NULL) {
            cout << "MyString(" << p << ")\n";
            // 计算传入参数的长度
            int str_len = strlen(p);
            data = (char*)malloc(str_len+1);
            strcpy(data, p);
        }
        // 拷贝构造函数,对指针执向的内容进行深度复制
        MyString(const MyString & src) {
            cout << "MyString(const MyString& src.data:" << src.data << ")\n";
            // 求源对象字符的长度
            int str_len = strlen(src.data);
            data = (char*) malloc(str_len+1);
            strcpy(data, src.data);
        }
        // 析构函数
        ~MyString(){
            cout << "~MyString(" << data << ")" << endl;
            free(data);
        }
        const char * c_str(void) {
            return data;
        }
    private:
        char * data;
};

int main(int argc, char * argv[]) {
    MyString s1 = "zhangsan";
    MyString s2 = s1;  // 调用拷贝构造函数
    MyString s3(s2);  // 调用拷贝构造函数

    cout << "s1:" << s1.c_str() << endl;
    cout << "s2:" << s2.c_str() << endl;

    cout << "程序结束!" << endl;
    return 0;
}

示例:

给MyString添加两个成员函数

class MyString{
    public:
    void copy(const char * content) {...}
    void copy(const MyString & src) {...}
};

使其修改 data 执行的内容,让器变为新的内容

参考

#include <iostream>
#include <stdlib.h>
#include <string.h>

using namespace std;

// 定义一个MyString类,使用动态数组来存储字符信息
class MyString {
    public:
        // 将字符串初始化成 n个内容为 c的字符
        MyString(char c, int n) {
            cout << "MyString(" << c << "," << n<<")\n";
            data = (char*)malloc(n+1);
            for (int i = 0; i < n; i++) {
                data[i] = c;
            }
            data[n] = '\0';
        }
        MyString(const char * p=""):data(NULL) {
            cout << "MyString(" << p << ")\n";
            // 计算传入参数的长度
            int str_len = strlen(p);
            data = (char*)malloc(str_len+1);
            strcpy(data, p);
        }
        // 拷贝构造函数,对指针执向的内容进行深度复制
        MyString(const MyString & src) {
            cout << "MyString(const MyString& src.data:" << src.data << ")\n";
            // 求源对象字符的长度
            int str_len = strlen(src.data);
            data = (char*) malloc(str_len+1);
            strcpy(data, src.data);
        }
        // 析构函数
        ~MyString(){
            cout << "~MyString(" << data << ")" << endl;
            free(data);
        }
        const char * c_str(void) {
            return data;
        }
    private:
        char * data;
    public:
        // 要求不能有内存泄漏
        void copy(const char * content) {
            // 释放自己原有的内存
            free(data);
            int str_len = strlen(content);
            data = (char*)malloc(str_len+1);
            strcpy(data, content);
        }
        void copy(const MyString & src){
            // 释放自己原有的内存
            free(data);
            int str_len = strlen(src.data);
            data = (char*)malloc(str_len+1);
            strcpy(data, src.data);
        }
};

int main(int argc, char * argv[]) {
    MyString s1 = "zhangsan";
    MyString s2;
    s2.copy(s1);
    cout << "s1:" << s1.c_str() << endl; // zhangsan
    cout << "s2:" << s2.c_str() << endl; // zhangsan
    s2.copy("lisi");
    cout << "s2:" << s2.c_str() << endl; // lisi 

    cout << "程序结束!" << endl;
    return 0;
}

C++ 成员函数的调用方式:

语法

对象.函数名(参数列表)
对象指针->函数名(参数列表)

面向对象编程(OOP)

OOP(Object Oriented Programming)

类:对象的描述(蓝图)

对象:类创建的实例,真正占用内存的变量。

思想:用类来描述对象的行为。用类封装对象数据。

描述方法:

有两个人(Human),张三(zhang3) 和 李四(li3)

张三工作赚钱 1000 元
李四借张三 300 元
李四买游戏机花了270元;
张三教李四玩王者荣耀
李四教张三 C++

用面相对象的思想来描述。

示例代码:

#include <iostream>
#include <stdlib.h>
#include <string.h>


using namespace std;

class Human {
    public:
        Human(const char * n) : name(n),money(0){}
        void showInfo(void) {
            cout << name << ", 有钱:" << money << "元, 技能:" << skill << endl;
        }
        void work(int m) {
            money += m;
            cout << name << " 工作赚了" << m << "元,共有"  << money << "元" << endl;
        }
        void borrowFrom(Human & h, int m) {
            if (m > h.money) {
                cout << h.name << "没有" << m << "元这么多钱,借钱失败!" << endl;
                return;
            }
            h.money -= m;
            money += m;
            cout << h.name << "借给" << name << m << "元钱!" << endl;
        }
    private:
        string name;
        int money;
        string skill; // 技能 :w

};

int main(int argc, char * argv[]) {
    // 有两个人(Human),张三(zhang3) 和 李四(li3)
    Human zhang3("张三");
    Human li4("李四");

    // 张三工作赚钱 1000 元
    // zhang3.work(1000);
    // 李四借张三 300 元
    li4.borrowFrom(zhang3, 300);
    zhang3.showInfo();
    li4.showInfo();
//    // 李四买游戏机花了270元;
//    li4.buy("游戏机", 270);
//    // 李四教张三玩王者荣耀
//    li4.teach(zhang3, "王者荣耀");
//    // 张三教李四 C++
//    zhang3.teach(li4, "C++");

    cout << "程序结束!" << endl;
    return 0;
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐