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





一、Visual Studio 中创建 String 类



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

在这里插入图片描述

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

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

#pragma once
class String
{
   
};

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

#include "String.h"




二、构造函数与析构函数




1、成员变量


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


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

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

	// 字符串指针, 指向堆内存中的字符串
	char* m_p;

代码示例 :

#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;
};

2、无参构造函数


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

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

m_len = 0;

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

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

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

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

代码示例 :

// 默认的无参构造函数
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;
}

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;
};

4、拷贝构造函数


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

首先 , 拷贝字符串长度 ;

  • 注意 : 字符串指针 指向的内存空间大小需要 +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);

代码示例 :

// 拷贝构造函数 , 使用 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;
}

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、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;
};

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;
	}
}

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;
}

4、执行结果


执行结果 :

调用无参构造函数
调用有参构造函数
调用拷贝构造函数
请按任意键继续. . .

在这里插入图片描述

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-11 19:20:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-11 19:20:01       101 阅读
  3. 在Django里面运行非项目文件

    2023-12-11 19:20:01       82 阅读
  4. Python语言-面向对象

    2023-12-11 19:20:01       91 阅读

热门阅读

  1. Linux watch命令监视命令输出

    2023-12-11 19:20:01       68 阅读
  2. QT实现的自定义进度条编程

    2023-12-11 19:20:01       69 阅读
  3. openssl编译和集成

    2023-12-11 19:20:01       97 阅读
  4. python一点通:参数列表里面有星号 * 什么意思?

    2023-12-11 19:20:01       115 阅读
  5. 力扣labuladong一刷day34天

    2023-12-11 19:20:01       58 阅读
  6. ubuntu apt指令集学习心得

    2023-12-11 19:20:01       47 阅读
  7. 动态规划算法介绍

    2023-12-11 19:20:01       83 阅读
  8. Oracle中decode函数使用

    2023-12-11 19:20:01       56 阅读
  9. MySQL面试

    2023-12-11 19:20:01       59 阅读
  10. 【redis笔记】分布式锁

    2023-12-11 19:20:01       60 阅读
  11. 理解Go语言中的defer

    2023-12-11 19:20:01       62 阅读