功能实现:
<基本功能>
1> 实现头文件的封装:MyString.h
2> 缺省构造函数对字符串的初始化( MyString() )
3> 使用构造函数初始化字符串的另外两种方式 * 2( 动态指针+拷贝构造函数 )
4> 析构函数( 释放动态申请的字符串空间 )
5> 重载输出运算符( << )
6> 重载赋值运算符 * 2( = )
7> 重载下标运算符( [],索引输出 )
<拓展功能>
1>
2>
3>
4>
5>
6>
7>
****************************************************************************************************************************************
一: 基本功能 (实现源码)
1) MyString.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h> //会借用strlen与strcpy函数实现相应的功能
using namespace std;
class MyString {
public:
MyString();
MyString(const char *const);
MyString(const MyString &);
~MyString();
int length()const; //const函数不能修改其数据成员,仅仅起到输出数据的作用
int size() const; //和length功能一致
const char * getString() const; //直接调用字符串首指针返回
friend ostream & operator << (ostream &, const MyString &); //重载输出运算符
MyString & operator = (const MyString &);
MyString & operator = (const char * );
char & operator [] (const int index);
private:
char * str; //指向数组首地址(此时为野指针)
int len;
};
2)MyString.cpp
#include "MyString.h"
using namespace std;
MyString::MyString() //构造空字符串
{
str = new char[1];
str[0] = '\0';
len = 0;
}
MyString::MyString(const char * const P) //按照动态指针来构造相应的字符串
{
if (P)
{
len = strlen(P); //取长度
str = new char[len + 1]; //开空间
strcpy(str, P); //复制值
}
else
{
MyString(); //如果传入的字符串为空,直接调用缺省值构造函数
}
}
MyString::MyString(const MyString & AnotherMyString) //拷贝构造函数,这里的形参使用了const,该形参类中的所有函数都要使用const来修饰
{
len = AnotherMyString.length();
str = new char[len + 1];
strcpy(str, AnotherMyString.str);
}
int MyString::length() const //求长度成员函数
{
return len;
}
int MyString::size() const
{
return len;
}
const char * MyString::getString()const
{
return str;
}
MyString & MyString::operator=(const MyString &AnotherMyString)
{
if (&AnotherMyString == this)
{
return *this;
}
delete[] str;
len = AnotherMyString.length();
str = new char[len + 1];
strcpy(str, AnotherMyString.str);
return *this;
// TODO: 在此处插入 return 语句
}
MyString & MyString::operator=(const char * P)
{
delete[] str;
len = strlen(P);
str = new char[len + 1];
strcpy(str, P);
return *this;
// TODO: 在此处插入 return 语句
}
char & MyString::operator[](const int index)
{
if (index > len) //如果索引越界,输出最后一个字符
{
cout << "Warning!!!" << endl;
cout << "Out of boundary! The last char is: ";
return str[len - 1];
}
else
{
return str[index-1];
}
// TODO: 在此处插入 return 语句
}
MyString::~MyString() //释放数组空间
{
delete[] str;
len = 0;
}
ostream & operator << (ostream & output, const MyString & str) //重载输出运算符
{
output << str.getString();
return output;
// TODO: 在此处插入 return 语句
}
*这里需要提到的一点是析构函数中的delete[] str;
<delete[]与delete的区别>
使用new得来的空间使用delete释放;使用new[]得来的空间使用delete[]释放;这是永远不会错的。
但是更加深入一点去理解:
使用new[]得到的空间如果 动态申请的数据类型时基本数据类型也可以使用delete直接释放,但是如果使用new[]申请的数据的类型时自定义类型(例如类名),这就必须使用delete[]来进行释放,只有这样才能够调用自定义类型的析构函数进行对自定义类型进行释放。
*除此之外,再提一点关于delete[]的注意事项:
当使用new[]动态生成内存的时候,删除的时候必须将删除的指针指向new[]出来的内存的首地址:
#include <iostream>
using namespace std;
int main()
{
int *p = new int[3];
*p = 1;
p++;
*p = 2;
delete[]p;
cout << "*" << endl;
return 0;
}
这一段小程序中:
因为p指针不是指向了首地址,所以程序虽然没报错,但是无法正常运行!我们可以将申请的首地址保存起来,供删除的时候使用。
3)test_main.cpp
#include "MyString.h"
using namespace std;
int main()
{
MyString a;
cout << "【调用缺省构造函数实现初始化】" << endl;
cout << "string a = " << a << endl;
cout << "Length = " << a.length() << endl << endl;
MyString b("123456");
cout << "【调用普通构造函数实现初始化】" << endl;
cout << "string b = " << b << endl;
cout << "Length = " << b.length() << endl << endl;
MyString c(b);
cout << "【调用拷贝构造函数实现初始化】" << endl;
cout << "string c = " << c << endl;
cout << "Length = " << c.length() << endl << endl;
MyString d = b; //这里不会再次调用缺省构造函数进行初始化
cout << "【调用 =(对象) 实现赋值】" << endl;
cout << "string d = " << d << endl;
cout << "Length = " << d.length() << endl << endl;
MyString e = "00000000";
cout << "【调用 =(动态指针) 实现赋值】" << endl;
cout << "string d = " << e << endl;
cout << "Length = " << e.length() << endl << endl;
MyString f = "abcdefghijklmn";
char str = f[5];
cout << "【调用 [] 实现索引定位输出】" << endl;
cout << "f[5] = " << str << endl << endl;
return 0;
}