• 【C++】运算符重载案例 - 字符串类 ① ( Visual Studio 中创建 String 类 | 构造函数与析构函数 | 完整代码示例 )






    一、Visual Studio 中创建 String 类



    右键点击 " 解决方案资源管理器 " 中的 解决方案 名称 , 在弹出菜单中 , 选择 " 添加 / 类 " 选项 ;

    在这里插入图片描述

    输入 String 类名 , 然后点击右下角的 " 确定 " 按钮 ;

    在这里插入图片描述
    生成的 String.h 头文件内容为 :

    #pragma once
    class String
    {
    };
    
    • 1
    • 2
    • 3
    • 4

    生成的 String.cpp 实现内容为 :

    #include "String.h"
    
    • 1




    二、构造函数与析构函数




    1、成员变量


    定义 String 类的 构造函数 , 成员函数 与 成员变量 ;


    成员变量主要有 2 2 2 个 , 分别是

    • 字符串长度 int m_len ,
      • 注意 : 字符串长度 , 不包括 ‘\0’ , 实际内存占用空间大小 = 字符串长度 + 1 ;
    • 字符串指针 char* m_p , 字符串指针指向堆内存中的字符串 ;
    private:
    	// 字符串长度 , 不包括 '\0'
    	// 内存占用空间大小 = 字符串长度 + 1
    	int m_len;
    
    	// 字符串指针, 指向堆内存中的字符串
    	char* m_p;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    代码示例 :

    #pragma once
    
    #include "iostream"
    using namespace std;
    
    class String
    {
    public:
    	// 默认的无参构造函数
    	String();
    
    	// 有参构造函数 , 接收一个 char* 类型字符串指针
    	String(const char* p);
    
    	// 拷贝构造函数 , 使用 String 对象初始化 对象值
    	String(const String& s);
    
    	// 析构函数
    	~String();
    
    private:
    	// 字符串长度 , 不包括 '\0'
    	// 内存占用空间大小 = 字符串长度 + 1
    	int m_len;
    
    	// 字符串指针, 指向堆内存中的字符串
    	char* m_p;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    2、无参构造函数


    默认的无参构造函数中 , 默认构造空字符串 ;

    首先 , 设置 字符串长度为 0 , 这里的 字符串指针 指向的内存空间大小是 1 , 内容是 ‘\0’ ;

    m_len = 0;
    
    • 1

    然后 , 分配内存 , 使用 new 关键字为 char* m_p; 指针分配内存 ;

    • 对于基础数据类型 new 等同于 malloc ;
    • 对于自定义类型 , new 会自动调用构造函数 , delete 会自动调用析构函数 ;
    m_p = new char[m_len + 1];
    
    • 1

    最后 , 拷贝空字符串到 m_p 指向的内存中 ;

    	// 拷贝空字符串到 m_p 指向的内存中
    	strcpy(m_p, "");
    
    • 1
    • 2

    代码示例 :

    // 默认的无参构造函数
    String::String()
    {
    	// 默认构造一个空字符串 , 字符串长度为 0 
    	// 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'
    	m_len = 0;
    
    	// 使用 new 关键字为 char* m_p; 指针分配内存
    	// 对于基础数据类型 new 等同于 malloc
    	m_p = new char[m_len + 1];
    
    	// 拷贝空字符串到 m_p 指向的内存中
    	strcpy(m_p, "");
    
    	cout << "调用无参构造函数" << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3、有参构造函数


    有参构造函数 , 接收一个 char* 类型字符串指针 ;

    需要分 2 2 2 种情况进行讨论 ,

    • 如果传入为 NULL , 就创建 空 字符串 ;
    • 如果传入非空字符串 , 测量字符串长度 , 分配内存 , 并拷贝字符串 ;

    代码示例 :

    // 有参构造函数 , 接收一个 char* 类型字符串指针
    String::String(const char* p)
    {
    	if (p == NULL)
    	{
    		// 默认构造一个空字符串 , 字符串长度为 0 
    		// 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'
    		this->m_len = 0;
    
    		// 使用 new 关键字为 char* m_p; 指针分配内存
    		// 对于基础数据类型 new 等同于 malloc
    		this->m_p = new char[this->m_len + 1];
    
    		// 拷贝空字符串到 m_p 指向的内存中
    		strcpy(m_p, "");
    	}
    	else
    	{
    		// 获取传入字符串的长度
    		// 但是 , 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
    		this->m_len = strlen(p);
    
    		// 使用 new 关键字为 char* m_p; 指针分配内存
    		// 对于基础数据类型 new 等同于 malloc
    		this->m_p = new char[this->m_len + 1];
    
    		// 拷贝字符串到 m_p 指向的内存中
    		strcpy(m_p, p);
    	}
    	cout << "调用有参构造函数" << endl;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    4、拷贝构造函数


    在 拷贝构造函数中 , 使用 String 对象初始化 对象值 ;

    首先 , 拷贝字符串长度 ;

    • 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 ‘\0’ ;
    this->m_len = s.m_len;
    
    • 1

    然后 , 使用 new 关键字为 char* m_p; 指针分配内存 , 对于基础数据类型 new 等同于 malloc ;

    this->m_p = new char[this->m_len + 1];
    
    • 1

    最后 , 拷贝字符串到 m_p 指向的内存中 ;

    strcpy(this->m_p, s.m_p);
    
    • 1

    代码示例 :

    // 拷贝构造函数 , 使用 String 对象初始化 对象值
    String::String(const String& s)
    {
    	// 拷贝字符串长度
    	// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
    	this->m_len = s.m_len;
    
    	// 使用 new 关键字为 char* m_p; 指针分配内存
    	// 对于基础数据类型 new 等同于 malloc
    	this->m_p = new char[this->m_len + 1];
    
    	// 拷贝字符串到 m_p 指向的内存中
    	strcpy(this->m_p, s.m_p);
    
    	cout << "调用拷贝构造函数" << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    6、析构函数


    析构函数中 , 使用 delete 释放之前使用 new 分配的内存 ;


    代码示例 :

    // 析构函数
    String::~String()
    {
    	if (this->m_p != NULL)
    	{
    		// 之前使用 new 分配的内存
    		// 释放内存就需要使用 delete 
    		// 使用 malloc 分配的内存需要使用 free 释放
    		delete[] this->m_p;
    
    		// 设置指针指为空 , 避免出现野指针
    		this->m_p = NULL;
    
    		// 设置字符串长度为 0
    		this->m_len = 0;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17




    三、完整代码示例




    1、String.h 类头文件


    #pragma once
    
    #include "iostream"
    using namespace std;
    
    class String
    {
    public:
    	// 默认的无参构造函数
    	String();
    
    	// 有参构造函数 , 接收一个 char* 类型字符串指针
    	String(const char* p);
    
    	// 拷贝构造函数 , 使用 String 对象初始化 对象值
    	String(const String& s);
    
    	// 析构函数
    	~String();
    
    private:
    	// 字符串长度 , 不包括 '\0'
    	// 内存占用空间大小 = 字符串长度 + 1
    	int m_len;
    
    	// 字符串指针, 指向堆内存中的字符串
    	char* m_p;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    2、String.cpp 类实现


    // 使用 strcpy 函数报错
    // error C4996: 'strcpy': This function or variable may be unsafe. 
    // Consider using strcpy_s instead. 
    // To disable deprecation, use _CRT_SECURE_NO_WARNINGS. 
    // See online help for details.
    #define _CRT_SECURE_NO_WARNINGS
    
    #include "String.h"
    
    // 默认的无参构造函数
    String::String()
    {
    	// 默认构造一个空字符串 , 字符串长度为 0 
    	// 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'
    	m_len = 0;
    
    	// 使用 new 关键字为 char* m_p; 指针分配内存
    	// 对于基础数据类型 new 等同于 malloc
    	m_p = new char[m_len + 1];
    
    	// 拷贝空字符串到 m_p 指向的内存中
    	strcpy(m_p, "");
    
    	cout << "调用无参构造函数" << endl;
    }
    
    // 有参构造函数 , 接收一个 char* 类型字符串指针
    String::String(const char* p)
    {
    	if (p == NULL)
    	{
    		// 默认构造一个空字符串 , 字符串长度为 0 
    		// 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'
    		this->m_len = 0;
    
    		// 使用 new 关键字为 char* m_p; 指针分配内存
    		// 对于基础数据类型 new 等同于 malloc
    		this->m_p = new char[this->m_len + 1];
    
    		// 拷贝空字符串到 m_p 指向的内存中
    		strcpy(m_p, "");
    	}
    	else
    	{
    		// 获取传入字符串的长度
    		// 但是 , 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
    		this->m_len = strlen(p);
    
    		// 使用 new 关键字为 char* m_p; 指针分配内存
    		// 对于基础数据类型 new 等同于 malloc
    		this->m_p = new char[this->m_len + 1];
    
    		// 拷贝字符串到 m_p 指向的内存中
    		strcpy(m_p, p);
    	}
    	cout << "调用有参构造函数" << endl;
    };
    
    // 拷贝构造函数 , 使用 String 对象初始化 对象值
    String::String(const String& s)
    {
    	// 拷贝字符串长度
    	// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
    	this->m_len = s.m_len;
    
    	// 使用 new 关键字为 char* m_p; 指针分配内存
    	// 对于基础数据类型 new 等同于 malloc
    	this->m_p = new char[this->m_len + 1];
    
    	// 拷贝字符串到 m_p 指向的内存中
    	strcpy(this->m_p, s.m_p);
    
    	cout << "调用拷贝构造函数" << endl;
    }
    
    // 析构函数
    String::~String()
    {
    	if (this->m_p != NULL)
    	{
    		// 之前使用 new 分配的内存
    		// 释放内存就需要使用 delete 
    		// 使用 malloc 分配的内存需要使用 free 释放
    		delete[] this->m_p;
    
    		// 设置指针指为空 , 避免出现野指针
    		this->m_p = NULL;
    
    		// 设置字符串长度为 0
    		this->m_len = 0;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    3、Test.cpp 测试类


    #include "iostream"
    using namespace std;
    
    // 导入自定义的 String 类
    #include "String.h"
    
    int main() {
    
    	// 调用无参构造函数
    	String s1;
    
    	// 调用有参构造函数
    	String s2("Tom");
    
    	// 调用拷贝构造函数
    	String s3 = s2;
    	
    
    	// 控制台暂停 , 按任意键继续向后执行
    	system("pause");
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4、执行结果


    执行结果 :

    调用无参构造函数
    调用有参构造函数
    调用拷贝构造函数
    请按任意键继续. . .
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

  • 相关阅读:
    linux学习-用户组管理
    基于3D视觉的智能鞋底涂胶机器人
    WordPress Mixed Content混合内容警告:4 种简单的修复方法
    Hello SpringSecurity
    如何将数据输入神经网络,神经网络的数据预处理
    springboot整合redis集群
    MySQL学习笔记5——函数和索引
    Re50:读论文 Large Language Models Struggle to Learn Long-Tail Knowledge
    MIPS64乘法器模拟实验
    docker给已存在的容器添加或修改端口映射
  • 原文地址:https://blog.csdn.net/han1202012/article/details/133703285