C++字符串類的封裝你真的了解嗎
字符串類的封裝
常規(guī)代碼
頭文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class MyString//字符串應(yīng)該是維護(hù)著一個(gè)字符數(shù)組的,在堆區(qū)
{
public:
MyString(const char* str);//有參構(gòu)造函數(shù)
MyString(const MyString& str);//拷貝構(gòu)造函數(shù)
~MyString();//析構(gòu)函數(shù)(是需要的,因?yàn)檫@個(gè)類中還維護(hù)著一個(gè)指針,需要自己釋放)
private:
char* pString;//維護(hù)在堆區(qū)開(kāi)辟的字符數(shù)組
int m_Size;//字符串長(zhǎng)度(不統(tǒng)計(jì)\0)
};
在頭文件中定義了MyString類中應(yīng)該有的屬性和三個(gè)函數(shù)。(有參構(gòu)造函數(shù)接收字符串并創(chuàng)建對(duì)象)(拷貝構(gòu)造函數(shù)可以接收同類型的對(duì)象并且復(fù)制出一個(gè)新的對(duì)象)(析構(gòu)函數(shù)負(fù)責(zé)在釋放掉本對(duì)象的同時(shí)釋放掉對(duì)象中維護(hù)的指針)
函數(shù)實(shí)現(xiàn)文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"myString.h";
//MyString str = "123";
MyString::MyString(const char* str)//有參構(gòu)造函數(shù),傳進(jìn)去的參數(shù)是一個(gè)字符串,返回的是MyString類型的對(duì)象。
{
cout<<"MyString的有參構(gòu)造函數(shù)調(diào)用"<<endl;
this->pString = new char[strlen(str) + 1];//給本對(duì)象的pString準(zhǔn)備空間。
strcpy(this->pString, str);//將傳進(jìn)來(lái)帶的字符串的地址也傳給本對(duì)象的pString處,str是字符串,不能調(diào)用pString屬性。
this->m_Size = strlen(str);
}
MyString::MyString(const MyString& str)//拷貝構(gòu)造函數(shù)
{
//這個(gè)需要深拷貝,因?yàn)轭愔杏袀€(gè)指針。注意:深拷貝是對(duì)指針進(jìn)行的深拷貝,也就是會(huì)傳進(jìn)來(lái)個(gè)對(duì)象,然后給這個(gè)對(duì)象中的指針 分配傳進(jìn)來(lái)的對(duì)象中的指針的大小的空間,然后將這個(gè)值也賦值到本指針中。
cout << "MyString的拷貝函數(shù)調(diào)用" << endl;
this->pString = new char[strlen(str.pString)+1];
strcpy(this->pString , str.pString);
this->m_Size = str.m_Size;
}
MyString::~MyString()//析構(gòu)(是需要的,因?yàn)檫@個(gè)類中還維護(hù)著一個(gè)指針,需要自己釋放)
{
cout << "MyString的析構(gòu)函數(shù)調(diào)用" << endl;
if (this->pString != NULL)
{
delete[] this->pString;
this->pString = NULL;
}
}
拷貝構(gòu)造和有參構(gòu)造的區(qū)別就是:
1,有參構(gòu)造傳進(jìn)去的是一個(gè)字符串,返回成一個(gè)對(duì)象。所以要的是對(duì)象的各個(gè)屬性與字符串的屬性的匹配。
2,拷貝構(gòu)造傳進(jìn)去的是一個(gè)對(duì)象,返回的也是一個(gè)對(duì)象,所以要的是傳進(jìn)來(lái)的對(duì)象和本對(duì)象(要?jiǎng)?chuàng)建的對(duì)象)之間屬性的對(duì)應(yīng)。
3,如果拷貝構(gòu)造的時(shí)候發(fā)現(xiàn)需要拷貝個(gè)指針,那么就不能直接使用編譯器的拷貝構(gòu)造函數(shù)了,因?yàn)榫幾g器的拷貝構(gòu)造函數(shù)構(gòu)造出來(lái)的對(duì)象的指針是和傳進(jìn)來(lái)的對(duì)象的指針是指向同一塊地方的,那么等到需要釋放指針的時(shí)候就會(huì)出現(xiàn)重釋放的錯(cuò)誤。**(這也是為什么需要自己重新創(chuàng)建拷貝構(gòu)造的原因)**如果類中不需要維護(hù)指針,那么就不需要自己寫(xiě)拷貝構(gòu)造(自己為指針再創(chuàng)建空間)。
Test文件
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include "myString.h";
int main()
{
MyString str = "abc";//調(diào)用默認(rèn)構(gòu)造
//和后面的一樣MyString str("abc");
MyString str2 = str;//調(diào)用拷貝構(gòu)造
return 0;
}
注意,這里的“abc”就是傳進(jìn)來(lái)的字符串str,然后這里的str就是創(chuàng)建出來(lái)的MyString類型的對(duì)象。
運(yùn)行的結(jié)果:
MyString的有參構(gòu)造函數(shù)調(diào)用
MyString的拷貝函數(shù)調(diào)用
MyString的析構(gòu)函數(shù)調(diào)用
MyString的析構(gòu)函數(shù)調(diào)用
重載左移>>
如果想進(jìn)行
cout<<str<<endl;代碼肯定會(huì)報(bào)錯(cuò),因?yàn)閟tr是MyString類型的對(duì)象,<<不認(rèn)識(shí)這個(gè)。
所以,這個(gè)時(shí)候就需要重載一下<<左移運(yùn)算符,可以在函數(shù)文件中實(shí)現(xiàn)。(需要用全局函數(shù)配合友元進(jìn)行重載)
實(shí)現(xiàn)函數(shù):
ostream& operator<<(ostream& cout, MyString& str) //重載左移運(yùn)算符
{
cout << str.pString;//這里的pString是類中的私有屬性,所以需要在原類(在頭文件中)中給整個(gè)重載函數(shù)設(shè)置友元
return cout;
}
頭文件:
class MyString
{
friend ostream& operator<<(ostream& cout, MyString& str);//設(shè)置的友元
public:
private:
};
這樣cout << str << endl;這行代碼就可以調(diào)用了。
重載右移<<
如果想進(jìn)行
cin>>str;代碼肯定也會(huì)報(bào)錯(cuò),因?yàn)閟tr是MyString類型的對(duì)象,>>不認(rèn)識(shí)這個(gè)。
所以,這個(gè)時(shí)候就要重載一下>>右移運(yùn)算符,可以在函數(shù)文件中實(shí)現(xiàn)。(需要用全局函數(shù)配合友元進(jìn)行重載)
實(shí)現(xiàn)函數(shù):
istream& operator>>(istream& cin, MyString& str)//重載右移運(yùn)算符
{
//應(yīng)該先清空原來(lái)的堆區(qū)數(shù)據(jù)
if (str.pString)//這里的pString是對(duì)象中的私有屬性,所以需要在原類中加上這個(gè)重載函數(shù)的友元聲明
{
delete[] str.pString;
str.pString = NULL;
}
//不用急著直接將輸入的內(nèi)容傳給pString,可以先開(kāi)辟臨時(shí)數(shù)組,記錄著輸入內(nèi)容。
char buf[1024];
cin >> buf;
//因?yàn)槭亲约褐剌d的函數(shù),剛才將str的pString刪除了,現(xiàn)在需要重新申請(qǐng)空間。
str.pString = new char[strlen(buf) + 1];
strcpy(str.pString, buf);
str.m_Size = strlen(buf);//別忘了還要把大小考進(jìn)str的size中,因?yàn)閭鬟M(jìn)來(lái)一串字符以后,對(duì)象中的長(zhǎng)度還保持著原先的長(zhǎng)度,所以需要進(jìn)行修改。
cout << str.m_Size << endl;
return cin;
}
頭文件:
class MyString//字符串應(yīng)該是維護(hù)著一個(gè)字符數(shù)組的,在堆區(qū)
{
friend istream& operator>>(istream& cin, MyString& str);
public:
private:
};
然后就能給str的pString賦值了。
重載右移運(yùn)算符的時(shí)候的清空原來(lái)字符串中的內(nèi)容好像不太重要,刪除了也能正常運(yùn)行。創(chuàng)建臨時(shí)數(shù)組記錄(數(shù)組大小夠大即可),然后將賦值,最后別忘了更改對(duì)象中的size。
重載賦值=
如果想進(jìn)行:
str2 = str1
直接將兩個(gè)對(duì)象進(jìn)行=運(yùn)行起來(lái)代碼肯定會(huì)崩,因?yàn)椋喝截惲?,刪除對(duì)象的時(shí)候會(huì)出現(xiàn)淺拷貝的問(wèn)題。
如果想進(jìn)行:
str2 = “abc"
直接將字符串賦值給字符串肯定也是不行的。
所以需要重載兩個(gè)不同參數(shù)的 = 運(yùn)算符。(一種參數(shù)是對(duì)象,一種參數(shù)是字符串)
MyString& operator=(const MyString& str); MyString& operator=(const char* str);
返回值必須要是MyString& ,因?yàn)槭褂猛?運(yùn)算符要返回的是自身(str2). 注意在頭函數(shù)中聲明完了以后到實(shí)現(xiàn)文件中去實(shí)現(xiàn)的時(shí)候要寫(xiě)范圍MyString::,而且這個(gè)類的范圍需要寫(xiě)在返回值類型的后面,函數(shù)名的前面。
重載=運(yùn)算符,與重載左移和右移運(yùn)算符不同,不用再像<<和>>一樣使用全局函數(shù)重載了,需要使用成員函數(shù)
頭文件:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class MyString
{
friend ostream& operator<<(ostream& cout, MyString& str);
friend istream& operator>>(istream& cin, MyString& str);
public:
MyString(const char* str);//有參構(gòu)造函數(shù)
MyString(const MyString& str);//拷貝構(gòu)造函數(shù)
~MyString();//析構(gòu)(是需要的,因?yàn)檫@個(gè)類中還維護(hù)著一個(gè)指針,需要自己釋放)
//重載兩個(gè)=運(yùn)算符
MyString& operator=(const MyString& str);
MyString& operator=(const char* str);
private:
char* pString;//維護(hù)在堆區(qū)開(kāi)辟的字符數(shù)組
int m_Size;//字符串長(zhǎng)度(不統(tǒng)計(jì)\0)
};
實(shí)現(xiàn)文件:
#define _CRT_SECURE_NO_WARNINGS 1
#include"myString.h";
MyString & MyString::operator=(const MyString & str)
{
//先判斷原堆區(qū)有沒(méi)有內(nèi)容,如果有先釋放。
if (this->pString)
{
delete[]this->pString;
this->pString = NULL;
}
//進(jìn)行深拷貝
this->pString = new char[strlen(str.pString) + 1];
strcpy(this->pString, str.pString);
this->m_Size = strlen(str.pString);
return *this;
}
MyString & MyString::operator=(const char* str)
{
//先判斷原堆區(qū)有沒(méi)有內(nèi)容,如果有先釋放。
if (this->pString)
{
delete[]this->pString;
this->pString = NULL;
}
//進(jìn)行深拷貝
this->pString = new char[strlen(str) + 1];
strcpy(this->pString, str);
this->m_Size = strlen(str);
return *this;
}
Test文件:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include "myString.h";
int main()
{
MyString str = "abc";//調(diào)用默認(rèn)構(gòu)造
MyString str2 = "bcd";
str = str2;
MyString str3 = "abc";
cout << str << endl;//bcd
cout << str3 << endl;//abc
return 0;
}
重載中括號(hào)[ ]
如果項(xiàng)進(jìn)行
str2[0] = 'a';
是不可以的,因?yàn)閇 ]不認(rèn)識(shí)str。
所以需要重載中括號(hào)[]。直接使用成員函數(shù)進(jìn)行重載。
//在頭文件中:
char operator[](int index);
//在實(shí)現(xiàn)函數(shù)中:
char MyString::operator[](int index)//重載中括號(hào)
{
return this->pString[index];
}
正常來(lái)說(shuō)就返回char類型的數(shù)值就行了,這樣就可讀了。
但是如果想將str2p[1]作為運(yùn)算左值來(lái)修改,那么就需要返回本體char&
//在頭文件中:
char& operator[](int index);
//在實(shí)現(xiàn)函數(shù)中:
char& MyString::operator[](int index)//重載中括號(hào)
{
return this->pString[index];
}
//在Test文件中
int main()
{
MyString str2 = "bcd";
cout << str2[1] << endl;//c
str2[1] = 'z';
cout << str2[1] << endl;//z
return 0;
}
重載加號(hào)+
如果想實(shí)現(xiàn):
MyString str3 = "abc"; MyString str4 = "def"; MyString str5 = str3 + str4; MyString str6 = str5+"abc";
這樣肯定會(huì)報(bào)錯(cuò),因?yàn)?不認(rèn)識(shí)對(duì)象,也不認(rèn)識(shí)這樣的字符串
所以,需要對(duì)+進(jìn)行重載,使用的還是成員函數(shù),只有一個(gè)參數(shù)。
從題意得,傳進(jìn)去一個(gè)對(duì)象,然后返回出一個(gè)對(duì)象,或者是傳進(jìn)去一個(gè)字符串,返回出一個(gè)對(duì)象。(前提是將第一個(gè)傳進(jìn)去的看作是調(diào)用對(duì)象)
頭文件:
MyString operator+(const MyString& str); MyString operator+(const char* str);
實(shí)現(xiàn)文件:
//重載+運(yùn)算符
MyString MyString:: operator+(const MyString& str)
{
//本身abc,傳入的是def,剛開(kāi)始應(yīng)該先計(jì)算一下需要開(kāi)辟的內(nèi)存空間。
int newSize = this->m_Size + strlen(str.pString) + 1;
char* temp = new char[newSize];//然后將這塊空間開(kāi)辟出來(lái),temp指針指向它。
memset(temp, 0, newSize);//將空間里面的內(nèi)容全部清空。
strcat(temp, this->pString);//將this->pString扔進(jìn)了temp中。
strcat(temp, str.pString);//然后再將str字符串扔進(jìn)去,這樣它們就自己結(jié)合了。
//但是創(chuàng)建好的新的字符串不能直接返回,因?yàn)樾枰祷匾粋€(gè)對(duì)象
//所以就創(chuàng)建一個(gè)新的對(duì)象,然后通過(guò)構(gòu)造函數(shù)將字符串賦給新對(duì)象,最后再返回新對(duì)象。
MyString newString = temp;
//還有一點(diǎn),創(chuàng)建的類是空間temp用完了需要釋放
delete[]temp;
return newString;
}
MyString MyString:: operator+(const char* str)
{
//本身abc,傳入的是def,剛開(kāi)始應(yīng)該先計(jì)算一下需要開(kāi)辟的內(nèi)存空間。
int newSize = this->m_Size + strlen(str) + 1;
char* temp = new char[newSize];//然后將這塊空間開(kāi)辟出來(lái),temp指針指向它。
memset(temp, 0, newSize);//將空間里面的內(nèi)容全部清空。
strcat(temp, this->pString);//將this->pString扔進(jìn)了temp中。
strcat(temp, str);//然后再將str字符串扔進(jìn)去,這樣它們就自己結(jié)合了。
//但是創(chuàng)建好的新的字符串不能直接返回,因?yàn)樾枰祷匾粋€(gè)對(duì)象
//所以就創(chuàng)建一個(gè)新的對(duì)象,然后通過(guò)構(gòu)造函數(shù)將字符串賦給新對(duì)象,最后再返回新對(duì)象。
MyString newString = temp;
//還有一點(diǎn),創(chuàng)建的類是空間temp用完了需要釋放
delete[]temp;
return newString;
}
兩種+重載函數(shù)幾乎一樣
TEST文件
int main()
{
MyString str3 = "abc";
MyString str4 = "def";
MyString str5 = str3 + str4;
MyString str6 = str5 + "abc";
cout << str5 << endl;//abcdef
cout << str6 << endl;//abcdefabc
return 0;
}
重載==
ps補(bǔ)充:strcmp函數(shù)中,如果兩個(gè)字符串相等,那么就返回0,如果不相等,那么就返回1。
也是提供兩種重載函數(shù):
//頭文件:
//重載==運(yùn)算符
bool operator==(const MyString& str);
bool operator==(const char* str);
//實(shí)現(xiàn)文件:
//重載==運(yùn)算符
bool MyString::operator==(const MyString & str)
{
if (strcmp(this->pString, str.pString) == 0)
return true;
else
return false;
}
bool MyString::operator==(const char* str)
{
if (strcmp(this->pString, str) == 0)
return true;
else
return false;
}
//Test文件
int main()
{
MyString str3 = "abc";
MyString str4 = "def";
MyString str5 = str3 + str4;
cout << str5 << endl;//abcdef
if (str5 == str5)
{
cout << "是相等的" << endl;
}
else
{
cout << "是不相等的" << endl;
}
//結(jié)果是相等的。
return 0;
}
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Opencv二幀差法檢測(cè)運(yùn)動(dòng)目標(biāo)與提取輪廓
這篇文章主要為大家詳細(xì)介紹了Opencv使用二幀差法檢測(cè)運(yùn)動(dòng)目標(biāo)與提取輪廓,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03
ros項(xiàng)目調(diào)試:vscode下配置開(kāi)發(fā)ROS項(xiàng)目的詳細(xì)教程
這篇文章主要介紹了ros項(xiàng)目調(diào)試:vscode下配置開(kāi)發(fā)ROS項(xiàng)目,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
C語(yǔ)言經(jīng)典算法例題求100-999之間的“水仙花數(shù)”
本文的主要內(nèi)容,設(shè)計(jì)一個(gè)程序,找出100-999之間的“水仙花數(shù)”,需要的朋友可以參考下2015-07-07
C++實(shí)現(xiàn)旋轉(zhuǎn)掃描儀的示例代碼
旋轉(zhuǎn)掃描儀(Rotating?Scanner),也稱為旋轉(zhuǎn)掃描儀或圓形掃描儀,是一種用于獲取圖像和文檔的設(shè)備,下面就跟隨小編一起來(lái)學(xué)習(xí)一下如何使用C++實(shí)現(xiàn)旋轉(zhuǎn)掃描儀功能吧2024-02-02
C語(yǔ)言變長(zhǎng)數(shù)組 struct中char data[0]的用法詳解
下面小編就為大家?guī)?lái)一篇C語(yǔ)言變長(zhǎng)數(shù)組 struct中char data[0]的用法詳解。小編覺(jué)得挺不錯(cuò)的現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01

