C++初階(運算符重載匯總+實例)
運算重載符
概念: 運算符重載是具有特殊函數名的函數,也具有其返回值類型,函數名字以及參數列表,其返回值類型與參數列表與普通的函數類似。
函數原型:
返回值 operator操作符(參數列表)
注意:
- 運算符重載,就是對已有的運算符重新進行定義,賦予其另外一種功能,以適應不同的數據類型
- 不能通過重載操作符來創建新的操作符,如operator@
- 必須含有一個類類型或枚舉類型的操作數
- 不能改變內置類型的含義
- 重載函數如果寫成成員函數,左側第一個參數隱含了一個Date* const this的形參,限定為第一個形參
- 重載函數如果寫成全局,那麼左邊是你輸入的第一個參數,右邊是第二個參數
- .*,::,?:,sizeof,.這五個運算符不能重載
注意以下幾點:
- 除了賦值號(=)之外,基類中被重載的操作符都將被派生類繼承
- =,[],(),->操作符只能通過成員函數進行重載
- << 和 >> 操作符最好通過友元進行重載
- 不要重載&&和||運算符,因為無法實現短路規則
選擇作為成員或非成員
當我們定義重載的運算符時,必須首先決定是將其聲明為類的成員函數還是聲明為一個普通的非成員函數。在某些時候我們別無選擇,因為有的運算符必須作為成員;另一些情況下,運算符作為普通函數比作為成員更好。
下面的準則有利於我們在運算符定義為成員函數還是普通的非成員函數做出抉擇:
- 賦值(=)、下標([ ])、調用(())和成員訪問箭頭)(->),運算符必須是成員
- 複合運算符一般來說是成員,但是非必須
- 改變成員狀態的運算符或者給定類型密切相關的運算符,比如遞增、遞減和解引用運算符,通常應該是成員
- 具有對稱性的運算符可能轉換任意一端的運算對象,例如算術、相等性、關係和位運算符等,因此他們通常應該是普通的非成員對象
賦值運算符重載
我們可以重載賦值運算符,無論形參的類型是什麼,賦值運算符都必須定義為成員函數
賦值運算符,賦值之後,左側運算對象和右側運算對象的值相等,並且運算應該返回它左側運算對象的一個引用
特性:
- 返回是*this
- 如果沒有顯示定義,編譯器也會生成一個,按位元組序拷貝
Date& operator=(const Date& d)
{
// 檢測是否自己給自己賦值
if (this == &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
實例:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream> //引入頭文件
#include<string>//C++中的字元串
using namespace std; //標準命名空間
class Maker
{
public:
Maker()
{
id = 0;
age = 0;
}
Maker(int id, int age)
{
this->id = id;
this->age = age;
}
public:
int id;
int age;
};
void test01()
{
Maker m1(10, 20);
Maker m2;
m2 = m1;
//默認的賦值運算符重載函數進行了簡單的賦值操作
//就類似於位元組序的淺拷貝
cout << m2.age << m2.id << endl;
}
class Student
{
public:
Student(const char * name)
{
pName = new char[strlen(name)+1];
strcpy(pName, name);
}
//防止淺拷貝
Student(const Student& stu)
{
pName = new char[strlen(stu.pName) + 1];
strcpy(pName, stu.pName);
}
//重寫賦值運算符重載函數
//為什麼要返回引用
Student& operator =(const Student& stu)//第一個參數默認是this指針
{
//1.不能確定this指向的空間是否能裝下stu中的數據,所以先釋放this指向的空間
if (this->pName!= NULL)
{
delete[] this->pName;
this->pName = NULL;
}
//2.釋放了之後再來申請堆區空間,大小由stu決定
this->pName = new char[(strlen(stu.pName) + 1)];
//3.拷貝函數
strcpy(this->pName, stu.pName);
//返回對象本身
return *this;//this中存放的是對象的地址,對地址取*表示對象本身
}
void printfStudent()
{
cout << this->pName << endl;
}
~Student()
{
delete[] pName;
pName = NULL;
}
public:
char* pName ;
};
void test02()
{
Student s1("悟空");
Student s2("唐僧");
Student s3("八戒");
s1 = s2 = s3;
s1.printfStudent();
s2.printfStudent();
s3.printfStudent();
cout << &(s2 = s3) << endl;
cout << &s2 << endl;
}
int main()
{
test01();
cout << "-------------------------------" << endl;
test02();
system("pause");
return EXIT_SUCCESS;
}
運行結果如下:
在程式碼中留下了一個問題,為什麼重載的賦值操作運算符要返回左側對象的引用呢?
從s1 = s2 = s3開始說,賦值運算符本來的寓意是s3賦值s2,s2賦值s1,也就是說s2=s3這個表達式要返回原來s2的對象,如果不是引用那麼s2將會生成一個新的對象,所以要返回引用
本質:Student &operator =(const Student& stu)這個函數返回的是return *this,如果加上引用Student & = *this;實際上就是this空間重新取了個名字
但是如果不是引用,那麼就是Student = *this,會重新生成一個對象。就比如 int &a = b和int a = b的區別,第一種返回的還是原來的b,第二個返回的就是新的a
算術運算符(加號)重載
一般來說,我們把算數和關係運算符定義成非成員函數以允許對左側或者右側的運算對象進行轉換。因為這些運算符一般不需要改變運算對象的狀態,所以形參都是常量的引用。
下面的程式碼從成員函數和非成員函數都介紹算術運算符的重載
#define _CRT_SECURE_NO_WARNINGS
#include<iostream> //引入頭文件
#include<string>//C++中的字元串
using namespace std; //標準命名空間
class Maker
{
public:
Maker(int id, int age)
{
this->age = age;
this->id = id;
}
//1.成員函數,就需要一個參數,這個參數就是加號的右邊
Maker operator+(const Maker& m2)
{
//加號左邊變成this
Maker temp(this->id + m2.id, this->age + m2.age);
return temp;//返回的時候調用拷貝構造
}
public:
int id;
int age;
};
//2.全局的方式
//編譯器會調用這個函數,編譯器會檢查參數是否對應
Maker operator+(Maker& m1, Maker &m2)
{
Maker temp(m1.id + m2.id, m1.age + m2.age);//調用有參構造
return temp;//返回的時候會調用拷貝構造
}
void test()
{
Maker m1(1, 20);
Maker m2(2, 22);
//m1+m2顯然是不可以的,要重載運算符
Maker m3 = m1 + m2;//編譯器看到兩個對象相加,編譯器會去找有沒有operator+函數
cout << m3.id << endl;
cout << m3.age << endl;
}
int main()
{
test();
system("pause");
return EXIT_SUCCESS;
}
運行結果如下:
關係運算符重載
bool operator == (Maker &m)
{
if(this->id == m.id && this->age == m.age){
return true;
}
return false;
}
輸出和輸入運算符重載
輸出 << 運算符 的重載
輸出運算符應該主要負責列印對象的內容而非控制格式,輸出運算符不應該列印換行符
輸出運算符的第一個形參是一個非常量ostream對象的引用,之所以ostream是個非常量是因為向流寫入內容會改變其狀態;而該形參是引用是因為我們無法直接複製一個ostream對象
第二個形參一般來說是一個常量的引用,該常量就是我們想要列印的類類型。第二個形參是引用是因為我們希望避免複製實參;而之所以該形參可以是常量是因為通常情況下列印對象不會改變對象的內容
#define _CRT_SECURE_NO_WARNINGS
#include<iostream> //引入頭文件
#include<string>//C++中的字元串
using namespace std; //標準命名空間
class Maker
{
//友元函數
friend ostream& operator <<(ostream& out, Maker& m);
public:
Maker(int id, string name)
{
this->id = id;
this->name = name;
}
private:
int id;
string name;
};
//1.形參和實參是一個對象,因為用的是引用,只是對同一塊空間取別名
//2.對 << 運算符進行重載,左邊是ostream對象,右邊是Maker對象
//3.一定要用引用,因為ostream把拷貝構造函數私有化了
//4.如果要和endl一起用,那麼就必須返回ostream
ostream& operator << (ostream& out, Maker& m)
{
cout << m.id << " " << m.name << endl;
return out;
}
void test01()
{
Maker m(10, "小花");
cout << m;
cout << endl;
/*
endl是一個函數
operator << (函數指針)
operator(endl)把endl函數傳進來
*/
cout << 10;//在內部重載了基礎數據類型
}
int main()
{
test01();
system("pause");
return EXIT_SUCCESS;
}
輸入 >> 運算符的重載
輸入運算符必須處理輸入可能失敗的情況,而輸出運算符不需要
輸入運算符的第一個形參是運算符想要讀取的流的引用,第二個形參是將要讀入到的(非常量)對象的引用。該運算符通常會返回某個給定流的引用。第二個形參之所以必須是個非常量是因為輸入運算符本身的目的就是將數據讀入到這個對象中
#define _CRT_SECURE_NO_WARNINGS
#include<iostream> //引入頭文件
#include<string>//C++中的字元串
using namespace std; //標準命名空間
void test01()
{
int a;
cin >> a;//從鍵盤中獲取數據
cout << a << endl;
}
class Maker
{
//訪問私有成員要設置為友元函數
friend istream& operator >>(istream& in, Maker& m);
public:
Maker(string name, int age)
{
this->name = name;
this->age = age;
}
int getAge()
{
return age;
}
private:
string name;
int age;
};
//重載>>右移運算符
//同一個對象取別名
istream& operator >>(istream& in, Maker& m)
{
in >> m.age;
in >> m.name;
return in;
}
void test02()
{
Maker m("悟空", 15);
Maker m2("悟空2", 25);
cin >> m >> m2;
cout << m.getAge() << endl;
cout << m2.getAge() << endl;
}
int main()
{
test02();
system("pause");
return EXIT_SUCCESS;
}
前置++和後置++運算符重載
前置++和後置++最大的區別就是返回值不同,前置是返回變化之後的值,後置是返回變化之前的值,兩個在重載是,都是operator++,我們如何區分呢?
一般operator++默認是前置++,為了區分後置++,我們通常會在參數列表加一個佔位參數,且這個參數必須是int類型的,從而構造成函數重載。
- 前置和後置運算符應該返回遞增或者遞減後對象的引用,因為是在同一個對象上進行的操作
- 後置運算應該返回對象的原值,返回的形式是一個值而並非是引用
#define _CRT_SECURE_NO_WARNINGS
#include<iostream> //引入頭文件
#include<string>//C++中的字元串
using namespace std; //標準命名空間
class Person
{
public:
Person(string name, int age)
{
this->_name = name;
this->_age = age;
}
// 前置++
Person& operator++()
{
//傳入一個this指針
this->_age++;
return *this;// 返回變化之後的值,傳引用
}
// 後置++,佔位參數(必須是int)
Person operator++(int)
{
//後置++,先返回,後++
Person ret = *this;//調用拷貝構造,拷貝this的一個臨時備份,用於返回
this->_age++;//this也就是傳入的對象中的_age值會改變
return ret;// 返回變化之前的值,傳值,返回的時候也調用的是拷貝構造
}
void Print()
{
cout << _name << "-" << _age << endl;
}
private:
string _name;
int _age;
};
int main()
{
Person p("wxj", 19);
p.Print();
cout << "前置++" << endl;
// 前置++
Person ret = ++p;
ret.Print();
p.Print();
cout << "後置++" << endl;
// 後置++
ret = p++;
ret.Print();
p.Print();
return 0;
}
運行結果如下:
值得注意的是成員函數的操作運算符左邊第一個參數是Date* const this一個this指針,所以只要對this指針進行操作,並且返回的是引用,那麼依舊是同一個對象的值發生改變並且裡面的值也會發生改變。
數組下標重載
表示容器的類通常可以通過元素在容器中的位置訪問元素,這些類一般會定義下標運算符operator []
- 下標運算符必須是成員函數
如果一個類包含下標運算符,那麼它通常會定義兩個版本:一個返回普通引用,另一個是類的常量成員並且返回常量引用
返回值類型 & operator[ ] (參數);
const 返回值類型 & operator[ ] (參數) const;
使用第一種聲明方式,[ ]
不僅可以訪問元素,還可以修改元素。使用第二種聲明方式,[ ]
只能訪問而不能修改元素。在實際開發中,我們應該同時提供以上兩種形式,這樣做是為了適應 const 對象,因為通過 const 對象只能調用 const 成員函數,如果不提供第二種形式,那麼將無法訪問 const 對象的任何元素。
#include <iostream>
using namespace std;
class Array{
public:
Array(int length = 0);
~Array();
public:
int & operator[](int i);
const int & operator[](int i) const;
public:
int length() const { return m_length; }
void display() const;
private:
int m_length; //數組長度
int *m_p; //指向數組記憶體的指針
};
Array::Array(int length): m_length(length){
if(length == 0){
m_p = NULL;
}else{
m_p = new int[length];
}
}
Array::~Array(){
delete[] m_p;
}
int& Array::operator[](int i){
return m_p[i];
}
const int & Array::operator[](int i) const{
return m_p[i];
}
void Array::display() const{
for(int i = 0; i < m_length; i++){
if(i == m_length - 1){
cout<<m_p[i]<<endl;
}else{
cout<<m_p[i]<<", ";
}
}
}
int main(){
int n;
cin>>n;
Array A(n);
for(int i = 0, len = A.length(); i < len; i++){
A[i] = i * 5;
}
A.display();
const Array B(n);
cout<<B[n-1]<<endl; //訪問最後一個元素
return 0;
}
需要說明的是,B 是 const 對象,如果 Array 類沒有提供 const 版本的operator[ ]
,那麼編譯器就會報錯。雖然只是讀取對象的數據,並沒有試圖修改對象,但是它調用了非 const 版本的operator[ ]
,編譯器不管實際上有沒有修改對象,只要是調用了非 const 的成員函數,編譯器就認為會修改對象(至少有這種風險)。
例子1:數組類
在.h文件中將數組類的功能和成員進行聲明
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<iostream> //引入頭文件
#include<string>//C++中的字元串
using namespace std; //標準命名空間
class MyArray
{
public:
MyArray();
//拷貝函數,防止淺拷貝,因為有pArray需要開闢堆區空間
MyArray(const MyArray& arr);
MyArray(int capacity, int val = 0);//有參構造
//重寫賦值運算符重載函數
MyArray& operator = (const MyArray& m);
//要能當左右值
int& operator[](int dex);
~MyArray();
//頭插法
void PushFront(int val);
//尾插
void PushBack(int val);
//頭刪
void PopFront();
//尾刪
void PopBack();
//獲取數組元素個數
int Size();
//獲取數組容量
int Capacity();
//指定位置插入元素
void Insert(int pos, int val);
//獲取指定位置的值
int& Get(int pos);
//在指定位置修改
void Set(int pos, int val);
private:
int* pArray;//指向堆區空間,存儲數據
int mSize;//元素個數
int mCapacity;//容量
};
在.c文件中對聲明的函數進行封裝,並進行測試
#include "MyArray.h"
//構造函數
MyArray::MyArray()
{
this->mCapacity = 20;
this->mSize = 0;
this->pArray = new int[this->mCapacity];
for (int i = 0; i < this->mCapacity; i++)
{
this->pArray[i] = 0;
}
}
//析構函數
MyArray::~MyArray()
{
if (this->pArray != NULL)
{
delete[] this->pArray;
this->pArray = NULL;
}
}
//拷貝構造函數
MyArray::MyArray(const MyArray& arr)
{
this->mCapacity = arr.mCapacity;
this->mSize = arr.mSize;
//申請空間
this->pArray = new int[arr.mCapacity];
//拷貝數據
for (int i = 0; i < this->mSize; i++)
{
this->pArray[i] = arr.pArray[i];
}
}
MyArray::MyArray(int capacity, int val)
{
this->mCapacity = capacity;
this->mSize = capacity;
this->pArray = new int[capacity];
for (int i = 0; i < this->mSize; i++)
{
this->pArray[i] = val;
}
}
//頭插法
void MyArray::PushFront(int val)
{
//判斷容量是否已經滿了
if (this->mSize == this->mCapacity)
{
return;
}
//頭插法,數組元素全部後移
for (int j = this->mSize - 1; j >= 0; j--)
{
this->pArray[j + 1] = this->pArray[j];
}
//空出0的位置
this->pArray[0] = val;
//維護元素個數
this->mSize++;
}
//尾插
void MyArray::PushBack(int val)
{
//判斷容量是否已經滿了
if (this->mSize == this->mCapacity)
{
return;
}
//尾插法
this->pArray[this->mSize] = val;
this->mSize++;
}
//頭刪
void MyArray::PopFront()
{
//刪除第一個元素的數據,實際上就是整體前移,進行覆蓋
if (this->mSize == 0)
{
return;
}
for (int i = 0; i < mSize - 1; i++)
{
this->pArray[i] = this->pArray[i + 1];
}
this->mSize--;
}
//尾刪
void MyArray::PopBack()
{
if (this->mSize == 0)
{
return;
}
this->mSize--;
}
//獲取數據元素個數
int MyArray::Size()
{
return this->mSize;
}
//獲取數組容量
int MyArray::Capacity()
{
return this->mCapacity;
}
//指定位置插入
void MyArray::Insert(int pos, int val)
{
//滿了就無法添加
if (this->mSize == this->mCapacity)
{
return;
}
//如果位置不對,就插入到尾部
if (pos<0 || pos>this->mCapacity)
{
pos = this->mSize;
}
for (int i = this->mSize - 1; i >= pos; i++) {
this->pArray[i + 1] = this->pArray[i];
}
this->pArray[pos] = val;
//將pos的位置空出來
this->mSize++;
}
//獲取指定位置的值
int& MyArray::Get(int pos)
{
return this->pArray[pos];
}
//在指定位置修改
void MyArray::Set(int pos, int val)
{
if (pos<0 || pos>mCapacity - 1)
{
return;
}
this->pArray[pos] = val;
}
//重寫賦值運算符重載函數
MyArray& MyArray::operator=(const MyArray& m)
{
//1.釋放原來的空間
if (this->pArray != NULL)
{
delete[] this->pArray;
this->pArray = NULL;
}
this->mCapacity = m.mCapacity;
this->mSize = m.mSize;
//2.申請空間,大小m決定
this->pArray = new int[m.mCapacity];
//3.拷貝數據
for (int i = 0; i < this->mCapacity; i++)
{
this->pArray[i] = m.pArray[i];
}
return *this;
}
//重寫下標[]//要能當左值
int& MyArray::operator[](int i)
{
//賦值的時候++
/*
for (int i = 0; i < 20; i++)
{
arr[i] = i + 10;
}
for (int i = 0; i < 20; i++)
{
cout << arr[i] << endl;
}
*/
//this->mSize++;
if (this->mSize <= i)
{
this->mSize++;
}
return this->pArray[i];
}
void printMyArray(MyArray& arr)
{
for (int i = 0; i < arr.Size(); i++)
{
cout << arr.Get(i) << " ";
cout << endl;
}
}
void test01()
{
MyArray arr(20, 1);//調用有參構造
printMyArray(arr);
//修改數組中的值
for (int i = 0; i < arr.Size(); i++)
{
arr.Get(i) = i + 100;
}
printMyArray(arr);
//指定位置修改值
arr.Set(2, 0);
printMyArray(arr);
//測試是否發生淺拷貝
MyArray arr2 = arr;
printMyArray(arr2);
}
void test02()
{
MyArray arr;
//添加元素
for (int i = 0; i < 10; i++)
{
//尾插
arr.PushBack(i + 10);
}
//頭插
for (int i = 0; i < 9; i++)
{
arr.PushFront(i + 20);
}
//指定位置插入
arr.Insert(10, 100);
//列印
printMyArray(arr);
arr.PopBack();
arr.PopFront();
printMyArray(arr);
}
int main()
{
test01();
test02();
system("pause");
return EXIT_SUCCESS;
}
例子2:字元串類
在.h文件中將字元串類的功能和成員進行聲明
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<iostream> //引入頭文件
#include<string>//C++中的字元串
using namespace std; //標準命名空間
//要重載的內容
/*
MyString s1;
MyString s1;
MyString s3=s1+s2;重載加號,拷貝構造
MyString s3=s1+「hello」;重載加號
s4+=s3 重載+=
s4+="hello" 重載+=
cout<<s4<<endl;重載<<
cin>>s4;重載>>
*/
class MyString
{
friend ostream& operator<<(ostream& out, MyString& str);
friend istream& operator>>(istream& in, MyString& str);
public:
MyString();
//用戶可以設定初始化字元串,n個c組成的字元串
MyString(int n, char c);
MyString(const MyString& str);
MyString& operator=(const MyString& str);
MyString operator+(const MyString& str);
MyString operator+(const char* s);
MyString& operator+=(const MyString& str);
MyString& operator+=(const char* s);
int Size();
char& operator[](int index);
~MyString();
private:
char* pM;//指向堆區空間
int mSize;
};
在.c文件中對聲明的函數進行封裝,並進行測試
#include "Mystring.h"
//用戶可以設定初始化字元串,n個c組成的字元串
MyString::MyString()
{
this->pM = new char[1];
this->pM[0] = '\0';
this->mSize = 0;
}
//有參構造
MyString::MyString(int n, char c)
{
//多留出一個位置最後加上'\0'
this->pM = new char[n+1];
for (int i = 0; i < n; i++)
{
this->pM[i] = c;
}
this->pM[n] = '\0';
this->mSize = n;
}
//拷貝構造
MyString::MyString(const MyString& str)
{
this->pM = new char[strlen(str.pM) + 1];
strcpy(this->pM, str.pM);
this->mSize = str.mSize;
}
//賦值操作,返回原來的對象
MyString& MyString::operator=(const MyString& str)
{
//1.釋放原來的空間
delete[] this->pM;
this->pM = NULL;
//2.申請空間
this->pM = new char[strlen(str.pM) + 1];
//3.拷貝數據
strcpy(this->pM, str.pM);
this->mSize = str.mSize;
return *this;
}
MyString MyString::operator+(const MyString& str)
{
//s3=s1+s2,this是s1,str是s2
//1.獲取s2要開闢的空間大小
int newlen = this->mSize + str.mSize + 1;
//2.定義一個臨時變數
MyString tmp;
if (tmp.pM != NULL)
{
//2.釋放原來的空間
delete[] tmp.pM;
tmp.pM = NULL;
}
//3.申請新的空間
tmp.pM = new char[newlen];
memset(tmp.pM, 0, newlen);
tmp.mSize = this->mSize+str.mSize;
//4.追加字元到空間當中
strcat(tmp.pM, this->pM);
strcat(tmp.pM, str.pM);
return tmp;//返回的時候會調用拷貝構造
}
MyString MyString::operator+(const char *s)
{
int newlen = this->mSize + strlen(s);
//開闢空間
char* newspace = new char[newlen + 1];
memset(newspace, 0, newlen + 1);
//追加數據到空間
strcat(newspace, this->pM);
strcat(newspace, s);
MyString temp;
if (temp.pM != NULL)
{
delete[] temp.pM;
temp.pM = NULL;
}
temp.pM = newspace;
temp.mSize = newlen;
return temp;
}
MyString& MyString::operator+=(const MyString& str)
{
/*
s4+=s3;
*/
//1.獲取兩個字元串的總字元個數
int newlen = this->mSize + str.mSize;
//2.申請新空間
char* newspace = new char[newlen + 1];
memset(newspace, 0, newlen + 1);
//3.追加數據
strcat(newspace, this->pM);
strcat(newspace, str.pM);
//4.釋放本身的空間
if (this->pM!= NULL)
{
this->pM = NULL;
}
this->pM = newspace;
this->mSize = newlen;
return *this;
}
MyString& MyString::operator+=(const char* s)
{
//1.獲取兩個字元串的總字元個數
int newlen = this->mSize + strlen(s);
//2.申請新空間
char* newspace = new char[newlen + 1];
memset(newspace, 0, newlen + 1);
//3.追加數據
strcat(newspace, this->pM);
strcat(newspace, s);
//4.釋放本身的空間
if (this->pM != NULL)
{
this->pM = NULL;
}
this->pM = newspace;
this->mSize = newlen;
return *this;
}
int MyString::Size()
{
return this->mSize;
}
char& MyString::operator[](int index)
{
return this->pM[index];
}
MyString::~MyString()
{
if (this->pM != NULL)
{
delete[] this->pM;
pM = NULL;
}
}
//並不是類的成員函數
ostream& operator<<(ostream& out, MyString& str)
{
cout << str.pM;
return out;
}
istream& operator>>(istream& in, MyString& str)
{
//cin>>s4
//用戶輸入的字元串要儲存到s4.pM指向的堆區空間
//1.定義臨時空間
char tmp[1024] = { 0 };
//2.獲取用戶輸入的資訊
in >> tmp;
//3.釋放s4的空間
if (str.pM != NULL)
{
delete[] str.pM;
str.pM = NULL;
}
//4.申請新的空間
str.pM = new char[strlen(tmp) + 1];
memset(str.pM, 0, strlen(tmp) + 1);
//5.拷貝用戶輸入的資訊到堆區空間
strcpy(str.pM, tmp);
str.mSize = strlen(tmp);
return in;
}
//測試
void test()
{
MyString s1(10, 'a');
cout << s1 << endl;
MyString s2(3, 'b');
cout << s2 << endl;
MyString s3 = s1 + s2;
cout << s3 << endl;
MyString s4 = s3 + "hello";
cout << s4 << endl;
for (int i = 0; i < s4.Size(); i++)
{
cout << s4[i] << endl;
}
}
int main()
{
test();
system("pause");
return EXIT_SUCCESS;
}