一個案例理解C++面向物件之運算子過載
阿新 • • 發佈:2021-08-13
運算子過載是C++面向物件基礎知識,本文通過一個自定義的string類完全理解運算子過載並且能夠溫習const與引用的相關知識:
- 首先構造一個字串類,既然是字串類,基本的兩個屬性應該是必需的:字串和字串長度
// String類的組成
class String
{
private:
char* str;
int len;
}
- 其次為了完成字串的初始化需要定義建構函式,為了保證記憶體不洩露需要定義解構函式,為了保證深拷貝定義複製拷貝函式
class String { public: String(); String(char* s); ~String(); String(const String & s); }
- 為了完成字串的運算操作需要過載‘+’,‘*’,‘<<','>>'運算子
// 使用const成員函式實現右乘即“ str*3 <=> strstrstr ”的功能 String operator*(int num) const; // 使用成員函式實現賦值運算即“ String1 = String2 = "string" ”的功能 String & operator=(const String & s); // 使用成員函式實現中括號索引運算即“ String[1] ”的功能 char & operator[](int num); // 使用const成員函式實現常物件的中括號索引運算即“ String[1] ”的功能 const char & operator[](int num) const; // 使用友元函式過載實現左乘即“ 3*str <=> strstrstr ”的功能 friend String operator*(int num,const String & s); // 使用友元函式實現加法即“ str1+str2 <=> str1str2 ”的功能 friend String operator+(const String & s1,const String & s2); // 使用友元函式實現輸出即“ cout<<str ”的功能 friend std::ostream & operator<<(std::ostream & os,const String & s); // 使用友元函式實現輸入即“ cin>>str ”的功能 friend std::istream & operator>>(std::istream & is,String & s);
- 為了保證自定義String類和字串指標的等價轉換需要定義轉換函式
// 使用轉換函式完成類型別到字串指標的轉換即“ char* ch = String ”的功能
// 僅含一個引數的建構函式可以作為引數型別到類型別的轉換
// 使用explicit關鍵字限制只能進行強制型別轉換
explicit operator char*();
- 完整的String類的定義如下:
String.h
class String { private: char* str; int len; public: // 建構函式和解構函式 String(); String(char* s); ~String(); // 過載運算子 String operator*(int num) const; friend String operator*(int num,const String & s); friend String operator+(const String & s1,const String & s2); friend std::ostream & operator<<(std::ostream & os,const String & s); friend std::istream & operator>>(std::istream & is,String & s); // 強制型別轉換函式 explicit operator char*(); };
- 完整的實現為:
String.cpp
#include <iostream>
#include "String.h"
using namespace std;
String::String()
{
// 預設建構函式
str = new char[1]; // 保證解構函式delete的一致性
str[0] = '\0';
len = 0;
}
String::String(const char* s)
{
// 使用字串指標構造
len = strlen(s);
str = new char[len+1];
strcpy(str, s);
}
String::~String()
{
// 解構函式釋放記憶體
len = 0;
delete [] str;
}
String::String(const String & s)
{
// 複製建構函式
len = s.len;
delete [] str;
str = new char[len+1];
strcpy(str,s.str);
}
String String::operator*(int num) const
{
// 字串乘法(成員函式)
String result;
result.len=len*3;
delete [] result.str; // 釋放原有記憶體
result.str=new char[result.len+1];
result.str[0]='\0';
for(int i=0;i<num;i++)
result.str=strcat(result.str,str);
return result;
}
String & String::operator=(const String & s)
{
// 賦值過載函式需要注意:
// 1. 釋放以前的記憶體
// 2. 防止賦值給自身
// 3. 返回引用值
if(this == &s)
return *this;
len=s.len;
delete [] str;
str=new char[len+1];
strcpy(str,s.str);
}
char & String::operator[](int num)
{
// 中括號過載,因為結果可為可修改的左值,所以返回值為非const引用
return str[num];
}
const char & String::operator[](int num) const
{
// 中括號過載,適用於常物件的資料訪問
return str[num];
}
String operator*(int num,const String & s)
{
// 字串乘法(友元函式)
return s*num;
}
String operator+(const String & s1,const String & s2)
{
// 字串加法
String sum;
sum.len = s1.len + s2.len;
delete [] sum.str;
sum.str = new char[sum.len+1];
strcpy(sum.str,s1.str);
strcat(sum.str,s2.str);
}
ostream & operator<<(ostream & os,const String & s)
{
// 重定義<<
os<<s.str;
return os;
}
istream & operator>>(istream & is,String & s)
{
// 重定義>>
is>>s.str;
s.len=strlen(s.str);
}
String::operator char*()
{
// 轉換函式(String類->字串指標)
char* s=new char[len+1];
strcpy(s,str);
return s;
}
- 上述程式碼中涉及返回物件的選擇,const、引用和普通物件,需要從實際含義去理解