文章目录
一、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、执行结果
执行结果 :
调用无参构造函数
调用有参构造函数
调用拷贝构造函数
请按任意键继续. . .