简易写法:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;
class String{
private:
char* _data;
size_t _size;
public:
String()//这个是默认构造,默认就是一个空
: _data(new char[1])
{
*_data = '\0';//解引用
}
String(const char* data)//参数const
:_data(new char [strlen(data)+1])
,_size(strlen(data))
{
strcpy(_data, data);
}
String(const String& s)//参数const
{
String(s._data);
}
void Swap(String& s){//注意大写第一个字母
swap(_data, s._data);
swap(s._size, s._size);
}
String& operator=(String s)//参数值
{
Swap(s);
return *this;
}
String(String&& s){
_data = s._data;
s._data = nullptr;//移动构造记得置空
_size = s._size;
}
String& operator=(String&& s){//直接交换
if (_data){
delete[] _data;
_data = nullptr;
}
Swap(s);
return *this;
}
~String(){
if (_data){
delete[] _data;
}
_size = 0;
}
int Size(){
return _size;
}
const char* c_str()const {//const!!!!
return _data;
}
//上面的是基础,在可以增加[],==,<
char& operator[](size_t pos){
assert(pos < _size);
return _data[pos];
}
};
bool operator==(const String& s1, const String& s2){
return !strcmp(s1.c_str() ,s2.c_str());//返回值等于0就是相等
}
bool operator<(const String& s1, const String& s2){
int a=strcmp(s1.c_str(), s2.c_str());//返回大于等于0就不是小于
if (a<0){
return true;
}
return false;
}
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
class String{
private:
size_t _size; //无符号整数代表存储的大小
size_t _capacity;
char* _data; //具体用来存储的内存指针
static const size_t npos;//const static可以类内定义
public:
typedef char* iterator;
typedef const char* const_iterator;//代表着是一个指针指向了不可变的变量
iterator begin(){
return _data;
}
const_iterator begin() const{ //const可以作为重载的标志(返回值不可以)
return _data;
}
iterator end(){ //刚好是最后一个有效的下一个
return _data + _size;
}
const_iterator end()const{
return _data + _size;
}
//这个应该写一个无参构造当默认构造
String(const char* str = '\0')//一般是常量字符串来赋值的const
:_size(strlen(str))//strlen是不包括\0的字符串大小
, _capacity(_size)
, _data(new char[strlen(str) + 1])//new []用来初始化多个空间[个数]--这里要有/0
{
strcpy(_data, str);
}
void Swap(String& str){
swap(_data, str._data);
swap(_size, str._size);
swap(_capacity, str._capacity);
}
String(const String& str)//拷贝构造底层也是调用构造
:_size(0)//等会用来交换这些就置空
, _capacity(0)
, _data(nullptr)
{
cout << "拷贝构造" << endl;
String tmp(str._data);//随便来个第三方变量创造出空间和内容
Swap(tmp);//交换后tmp就为空了
}
~String(){
if (_data){//一定要判断,否则释放空指针
delete[] _data;//所有的都是new[]
}
_data = nullptr;//不用的最好变成空指针
_capacity = _size = 0;
}
bool operator==(const String& str){//这个传一个参数返回一个bool
if (_data == str._data&&_size == str._size&&_capacity == str._capacity)
return true;
return false;
}
//赋值运算符重载的返回值是引用提高效率,不加也可以过,
//+法运算符写在类外,返回的是值,如果返回引用就是返回局部变量的值,返回值的话会返回匿名对象(拷贝构造)
//利用传值调用拷贝构造,就不用新变量了
//弊端是不能加const,cosnt修饰的不能swap
String& operator=(String str){
Swap(str);
return *this;
}
/*String& operator=(const String& str){//形参也不能是const
if (*this == str){
return *this;
}
String tmp(str);//调用拷贝构造,拷贝构造底层是通过str的_data调用构造,不具有常性
Swap(tmp);//可以用来交换
return *this;
}*/
char& operator[](size_t a){//取下标要求可以通过下表修改所以是返回引用
assert(a < _size);//下标越界是需要assert的警告,assert内部是正确的范围
return _data[a];
}
const char& operator[](size_t a)const{
assert(a < _size);
return _data[a];
}
void reserve(size_t ch){//增容,就是修改_capacity的大小,参数就是需要改变的大小
if (_capacity < ch){//小于就不动
char* newp = new char[ch + 1];//这里有个+1没写 ch表示有效字符的最大个数不包括\0
//拷贝存数据的内容
strcpy(newp, _data);
delete[] _data;//释放原有内容,避免内存泄露
_data = newp;
_capacity = ch;
}
}
void resize(size_t ch, const char& a = '\0'){//改变_size的大小,不足用指定的符号补齐
if (_capacity < ch)//先看容量
reserve(ch);
if (_size < ch)
memset(_data + _size, a, sizeof(char)*(ch - _size));//太多了才填充字符,这个可不会填充_capacity
_size = ch;//修改size的大小
//忘记\0
_data[_size] = '\0';//数据一定要有结束标志
}
void push_back(const char&a = '\0'){
if (_size == _capacity){//证明满了需要增容
//三目运算符顺序
size_t newcapacity = _capacity == 0 ? 15 : 2 * _capacity;
reserve(newcapacity);//增容
}
_data[_size++] = a;//size没有存\0
_data[_size] = '\0';
}
void append(const char* str){//插入新的字符数组
if (_capacity < (strlen(str) + _size)){
//等于甚至也不需要增容。因为reserve自动申请多一个存储\0,而_capacity隐藏这个
//构造函数也会默认多申请一个空间用来存储\0
reserve(strlen(str) + _size);
}
memcpy(_data + _size, str, sizeof(char)*strlen(str));
//忘记更新size
_size += strlen(str);
_data[_size] = '\0';//注意新增
}
//+=需要写在类内。返回引用,提高效率,返回值需要调用一次拷贝构造
String& operator+=(const String& str){
cout << "operator +=" << endl;
append(str._data);
return *this;
}
String& operator+=(const char* str){
append(str);
return *this;
}
String& operator+=(const char& str){
push_back(str);
return *this;
}
void insert(size_t pos, const char& ch){//pos的下一个位置插入
assert(pos <= _size);//可以等于,忘写了
//size代表的是元素个数
if (_size == _capacity){
size_t newc = _capacity == 0 ? 1 : 2 * _capacity;
reserve(newc);
}
size_t idx = _size;
while (idx>pos-1){//pos的位置也要移动
_data[idx+1] = _data[idx];
--idx;
}
/*size_t idx = _size + 1;//从后向前移动,包括\0
while (idx>pos){
_data[idx] = _data[idx - 1];
idx--;
}*/
_data[pos] = ch;
++_size;
}
void insert(size_t pos, const char* ch){
assert(pos <= _size);
size_t len = strlen(ch);
if (len + _size > _capacity){
reserve(len + _size);
}
size_t idx = _size + len;
while (idx>pos+1){
_data[idx] = _data[idx - len];
idx--;
}
memcpy(_data + pos, ch, sizeof(char)*len);//不能strcpy-->会拷贝\0
_size += len;
}
void earse(size_t pos, size_t len = npos){
assert(pos <= _size);
//如果没有指定删除的大小或者需要全部删除后面的
if (pos + len >= _size || len == npos){
_size = pos;
_data[_size] = '\0';
}
else{
size_t idx = pos + len;
while (idx <= _size){
_data[idx - len] = _data[idx];
++idx;
}
_size -= len;
}
}
size_t find(const char* ch, size_t pos = 0){//pos是从这个位置之后查找
assert(pos < _size);
char* strpos = strstr(_data + pos, ch);
if (strpos){
return strpos - _data;//返回找到的位置(指针相减)
}
return npos;
}
String substr(size_t pos, size_t len = npos){//创建子串
assert(pos < _size);
if (pos + len >= _size || len == npos){
return String(_data + pos);//pos是一个数字,指针加数字是指针
}
else{
char* newc = new char[len + 1];
//char *newc=[len+1];栈申请需要高级编译器才能识别
memcpy(newc, _data + pos, sizeof(char)*len);
newc[len] = '\0';
delete[] newc;//这里不写会内存泄漏,写了会报错
return String(newc);
}
}
size_t size()const{
return _size;
}
size_t capacity()const{
return _capacity;
}
const char* c_str() const{
return _data;
}
friend ostream& operator<<(ostream& out, const String& str);
friend istream& operator>>(istream& cin, String& str);
};
const size_t String::npos = -1;
//以下属于普通函数,重载函数,不能通过str.operator<<来访问
//只能通过普通函数的访问形式访问
String operator+(const String& a, const String& b){//普通函数不能加string::
String str(a); //拷贝构造需要const,否则报错
//因为const可以接受const和非const,非const只能接受const
str += b;
return str;
}
String operator+(const String& a, const char* b){
String str(a);
str += b;
return str;
}
String operator+(const String& a, const char& b){
String str(a);
str += b;
return str;
}
bool operator<(const String& str1, const String& str2){
int a = strcmp(str1.c_str(), str2.c_str());//1>2--大于0 否则小于0
if (a<0){
return true;
}
return false;
}
bool operator==(const String& str1, const String& str2){
int a = strcmp(str1.c_str(), str2.c_str());
if (a == 0){
return true;
}
return false;
}
bool operator!=(const String& str1, const String& str2){
return !(operator== (str1, str2));
}
//这里是借助迭代器来实现的打印,没有访问类的私有成员,不用写友元
ostream& operator<<(ostream& out, String& str){
for (const auto ch : str){
out << ch;
}
return out;
}
//相比于输出流简单地输出,输入流相当于尾插string
istream& operator>>(istream& cin, String& str){
char ch;
while ((ch = cin.get()) != EOF){
if (ch == ' ' || ch == '\0')
break;
str += ch;
}
return cin;
}
void printffor(const String& str){//const是为了也同时可以打印const的字符串
//形参const走的就是const的迭代器
for (const char& a : str){ //const_it
cout << a;
}
cout << endl;
}
void printffor2(const String& str){
String::const_iterator it = str.begin();
while (it != str.end()){
cout << *it << " ";
++it;
}
cout << endl;
}
void test(){
String str1 = "hello";
String str2 = " world";
cout << str1 << endl;
cin >> str2;
cout << str2 << endl;
}
int main(){
test();
system("pause");
return 0;
}