当前位置: 首页 > article >正文

实现C++自定义的String类

一、简介

  • 采用了COW写时复制的方式实现,即在每个String类数据域之前用了4个字节的空间进行引用计数。通过拷贝构造函数或者赋值运算符函数进行赋值时不会重新开辟空间,只会对引用计数加一,当有修改操作时,才会重新开辟新的空间;
  • 内部定义了一个char类型的内部代理类,用于解决String类重载下标运算符后无法区分读写操作的问题。

二、头文件

#pragma once
#include <iostream>


class String {
	class CharProxy { // char类型的代理内部类
	public:
		CharProxy(int index, String &str);
		char &operator=(const char &c);
		friend std::ostream &operator<<(std::ostream &os, const CharProxy &charPorxy);
	private:
		int _index;	   // 下标
		String &_this; // 指向外部类对象
	};

public:
	String();
	String(const char *pstr);
	String(const String &str);
	~String();
	String &operator=(const String &str);
	String &operator=(const char *pstr);

	String &operator+=(const String &str);
	String &operator+=(const char *pstr);
	
	String::CharProxy operator[](std::size_t index);
	
	std::size_t size()const; // 字符串的长度
	const char* c_str()const; // 返回一个C风格的字符串
	
	friend bool operator==(const String &leftStr, const String &rightStr);
	friend bool operator!=(const String &leftStr, const String &rightStr);
	
	friend bool operator<(const String &leftStr, const String &rightStr);
	friend bool operator>(const String &leftStr, const String &rightStr);
	friend bool operator<=(const String &leftStr, const String &rightStr);
	friend bool operator>=(const String &leftStr, const String &rightStr);
	
	friend std::ostream &operator<<(std::ostream &os, const String &str);
    friend std::istream &operator>>(std::istream &is, String &str);

	int refCount(); // 返回引用计数

	friend std::ostream &operator<<(std::ostream &os, const CharProxy &charPorxy);
private:
	char *malloc(const char *pstr = nullptr); // 为字符串申请空间
	void release(); // 释放字符串的空间
	void initRefCount(); // 初始化引用计数
	void increaseRefCount(); //增加引用计数
	void decreaseRefCount(); // 减少引用计数
	static const int refCountLength = 4; // 引用计数所占字节数
	char * _pstr;
};

String operator+(const String &thisStr, const String &otherStr);
String operator+(const String &thisStr, const char *otherpStr);
String operator+(const char *thisPstr, const String &otherStr);

三、String实现

#include <cstring>
#include "08_MyString.hh"

using namespace std;

/**
 * 内部代理类有参构造函数 
*/
String::CharProxy::CharProxy(int index, String &str) :_index(index), _this(str) {
	cout << "CharProxy()" << endl;
}

/**
 * 重载内部代理类的赋值运算符=
*/
char &String::CharProxy::operator=(const char &c) {	
	cout << "char &operator=(const char &c)" << endl;
	if (_index < strlen(_this._pstr)) { // 未越界
		if (*(int*)(_this._pstr - refCountLength) > 1) { // 判断引用计数是否大于1
			_this.decreaseRefCount(); // 原空间引用计数-1
			char *newStr = _this.malloc(_this._pstr); // 开辟新空间
			strcpy(newStr, _this._pstr);				
			_this._pstr = newStr;
			_this.initRefCount(); // 初始化引用计数(此处时机一定要在赋值了新串之后)		
		}
		_this._pstr[_index] = c; // 修改元素
		return _this._pstr[_index];
	}else {
		static char nullchar = '\0';
		return nullchar;
	}	
}

/**
 * 重载内部代理类的输出运算符<<
*/
ostream &operator<<(std::ostream &os, const String::CharProxy &charPorxy) {
	if (charPorxy._index < strlen(charPorxy._this._pstr)) {
		os << charPorxy._this._pstr[charPorxy._index];
	}else {
		os << "out of range";
	}
	return os;
}

/**
 * 为字符串申请空间 
 * 初始化并偏移到数据的位置
*/
char *String::malloc(const char *pstr) { 
	if (pstr == nullptr) {
		return new char[1 + refCountLength]() + refCountLength; 
	} else {
		return new char[strlen(pstr) + 1 + refCountLength]() + refCountLength;
	}
}

/**
 * 释放字符串的空间
*/
void String::release() {
	decreaseRefCount();
	if (refCount() == 0) {
		delete [] (_pstr - refCountLength);
		_pstr = nullptr;
		cout << "release()......." << endl;
	}
}

/**
 * 初始化引用计数
*/
void String::initRefCount() {
	*(int*)(_pstr - refCountLength) = 1;
}

/**
 * 增加引用计数
*/
void String::increaseRefCount(){
	++*(int*)(_pstr - refCountLength);
}
/**
 * 减少引用计数
*/
void String::decreaseRefCount(){
	--*(int*)(_pstr - refCountLength);
}
/**
 * 返回引用计数
*/
int String::refCount() {
	return *(int*)(_pstr - refCountLength);
}

/**
 * 无参构造函数
*/
String::String()
: _pstr(malloc())
{
	initRefCount();
	strcpy(_pstr, "");	
	cout << "String()" << endl;
}

/**
 * 有参构造函数
*/
String::String(const char *pstr) 
: _pstr(malloc(pstr)) 
{
	initRefCount();
	strcpy(_pstr, pstr);
	cout << "String(const char *pstr) " << endl;
}

/**
 * 拷贝构造函数
*/
String::String(const String &str)
: _pstr(str._pstr) // 浅拷贝
{
	increaseRefCount();
	cout << "String(const String &str)" << endl;
}

/**
 * 析构函数
*/
String::~String() {
	release();
}

/**
 * 重载赋值运算符函数
*/
String &String::operator=(const String &str) {
	if (this != &str && strcmp(_pstr, str._pstr) != 0) { // 跳过自赋值 和相同字符串
		release();
		_pstr = str._pstr; // 浅拷贝	
		increaseRefCount();
	} 
	return *this; 
}
String &String::operator=(const char *pstr) {
	if (strcmp(_pstr, pstr) != 0) { // 跳过相同字符串
		release(); // 删除旧字符串
		_pstr = malloc(pstr); // 申请新空间 
		initRefCount(); // 初始化引用计数
		strcpy(_pstr, pstr); // 复制	
	}
	return *this;
}

/**
 * 重载+=
*/
String &String::operator+= (const String &str) {
	if (str._pstr != nullptr && strlen(str._pstr) > 0) {
		size_t newLen = strlen(_pstr) + strlen(str._pstr) + refCountLength + 1;
		char *newStr = new char[newLen]() + refCountLength; // 偏移到数据的位置
		strcat(newStr, _pstr);
		strcat(newStr, str._pstr);
		release(); // 删除旧字符串
		_pstr = newStr;
		initRefCount(); // 初始化引用计数(此处时机一定要在赋值了新串之后)
	}
	return *this;
}
String &String::operator+= (const char *pstr) {
	if (pstr != nullptr && strlen(pstr) > 0) {
		size_t newLen = strlen(_pstr) + strlen(pstr) + refCountLength + 1;
		char *newStr = new char[newLen]() + refCountLength; // 偏移到数据的位置
		strcat(newStr, _pstr);
		strcat(newStr, pstr);
		release(); // 删除旧字符串
		_pstr = newStr;
		initRefCount(); // 初始化引用计数(此处时机一定要在赋值了新串之后)
	}
	return *this;
}

/**
 * 重载下标运算符
*/
String::CharProxy String::operator[] (size_t index) {
	return String::CharProxy(index, *this);
}

/**
 * 获取字符串长度
*/
size_t String::size() const {
	return strlen(_pstr);
}

/**
 * 返回C风格字符串
*/
const char *String::c_str() const {
	return _pstr;
}

/**
 * 重载==
*/
bool operator==(const String &leftStr, const String &rightStr) {
	return strcmp(leftStr._pstr, rightStr._pstr) == 0 ? true : false;
}
/**
 * 重载!=
*/
bool operator!=(const String &leftStr, const String &rightStr) {
	return strcmp(leftStr._pstr, rightStr._pstr) != 0 ? true : false;
}
/**
 * 重载<
*/
bool operator<(const String &leftStr, const String &rightStr) {
	return strcmp(leftStr._pstr, rightStr._pstr) < 0 ? true : false;
}
/**
 * 重载>
*/
bool operator>(const String &leftStr, const String &rightStr) {
	return strcmp(leftStr._pstr, rightStr._pstr) > 0 ? true : false;
}
/**
 * 重载<=
*/
bool operator<=(const String &leftStr, const String &rightStr) {
	int res = strcmp(leftStr._pstr, rightStr._pstr); 
	return res > 0 ? false : true;
}
/**
 * 重载>=
*/
bool operator>=(const String &leftStr, const String &rightStr) {
	int res = strcmp(leftStr._pstr, rightStr._pstr); 
	return res < 0 ? false : true;
}

/**
 * 重载输出流函数
*/
ostream &operator<< (ostream &os, const String &str) {
	os << str._pstr;
	return os;
}

/**
 * 重载输入流函数
*/
istream &operator>> (istream &is, String &str) {
	if (strlen(str._pstr) > 0) {
		str = ""; // str非空就先清空str
	}
	char buf[1024];
	while (1) {
		is.clear(); // 恢复流的状态
		bzero(buf, sizeof(buf)); // 清空buf
		is.get(buf, sizeof(buf)); // 读取一个buf的大小
		int len = strlen(buf);
		if (len == 0) { // buf长度为0时退出循环 
			break;
		}	
		str += buf;
	}
	return is;
}

/**
 * 重载+
*/
String operator+(const String &thisStr, const String &otherStr) {
	if (strlen(thisStr.c_str()) == 0) {
		return otherStr;
	}
	if (strlen(otherStr.c_str()) == 0) {
		return thisStr;
	}
	String temp(thisStr);
	temp+=otherStr;
	return temp;
}
String operator+(const String &thisStr, const char *otherPstr) {
	if (strlen(thisStr.c_str()) == 0) {
		return String(otherPstr);
	}
	if (strlen(otherPstr) == 0) {
		return thisStr;
	}
	String temp(thisStr);
	temp+=otherPstr;
	return temp;
}
String operator+(const char *thisPstr, const String &otherStr) {
	if (strlen(thisPstr) == 0) {
		return otherStr;
	}
	if (strlen(otherStr.c_str()) == 0) {
		return String(thisPstr);
	}
	String temp(thisPstr);
	temp+=otherStr;
	return temp;
}

http://www.kler.cn/news/272941.html

相关文章:

  • 47.全排列II
  • Java微服务分布式事务框架seata
  • 【Mysql事务】
  • 用python如何实现智能合约?如何使用remix编写solidity智能合约并部署上链
  • 【how2j练习题】HTML部分综合练习
  • (二十五)Flask之MTVMVC架构模式Demo【重点:原生session使用及易错点!】
  • 消息队列面试题
  • 2024西工大数据结构理论上机作业(头歌 C)持续更新中~
  • 寻找可能认识的人
  • 安卓面试网络知识基础 1-5
  • ​LeetCode解法汇总303. 区域和检索 - 数组不可变
  • 【已解决】MySQL:常用的除法运算+精度处理+除数为0处理
  • 强化PaaS平台应用安全:关键策略与措施
  • C++ 11:基于范围的 for 循环
  • java的23种设计模式03-创建型模式02-抽象工厂方法
  • 【解读】Gartner 2023 DevOps平台魔法四象限
  • postgres 客户端请求处理1——创建保存监听套接字
  • JDBC的概念
  • C语言选择语句概览
  • 用python写网络爬虫:2.urllib库的基本用法