一 短整形運算符重載
二 模拟String類運算符重載
三 SmallInt類運算符重載
四 explicit關鍵字
五 啞成員
一
短整形運算符重載
//短整形運算符重載
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>
using namespace std;
class Int
{
public:
Int(long i = 0) : m_i(i)
{}
Int(const Int& x)
{
this->m_i = x.m_i;
}
public:
Int operator+(const Int& x)
{
return Int(this->m_i + x.m_i);
}
Int operator-(const Int& x)
{
return Int(this->m_i - x.m_i);
}
Int operator*(const Int& x)
{
return Int(this->m_i * x.m_i);
}
Int operator/(const Int& x)
{
return Int(this->m_i / x.m_i);
}
Int operator%(const Int& x)
{
return Int(this->m_i % x.m_i);
}
public:
Int& operator+=(const Int& x) // a += b;
{
this->m_i += x.m_i;
return *this;
}
Int& operator-=(const Int& x)
{
this->m_i -= x.m_i;
return *this;
}
Int& operator*=(const Int& x)
{
this->m_i *= x.m_i;
return *this;
}
Int& operator/=(const Int& x)
{
this->m_i /= x.m_i;
return *this;
}
Int& operator%=(const Int& x)
{
this->m_i %= x.m_i;
return *this;
}
public:
Int operator>>(const Int& x) //a >> b
{
return Int(this->m_i >> x.m_i);
}
Int operator<<(const Int& x)
{
return Int(this->m_i << x.m_i);
}
Int& operator>>=(const Int& x)
{
this->m_i >>= x.m_i;
return *this;
}
Int& operator<<=(const Int& x)
{
this->m_i <<= x.m_i;
return *this;
}
public:
bool operator==(const Int& x)
{
if (this->m_i == x.m_i)
return true;
return false;
}
bool operator!=(const Int& x)
{
if (this->m_i != x.m_i)
return true;
return false;
}
public:
Int& operator++() //前置++ 比後置++效率 可以引用傳回
{
this->m_i++;
return *this;
}
Int operator++(int) //後置++
{
Int temp(*this); //調用拷貝構造函數或:
//Int tmp(this->m_i); //用構造函數
this->m_i++; //*this++
return temp;
}
Int& operator--() //前置-- 比後置++效率 可以引用傳回
{
this->m_i--;
return *this;
}
Int operator--(int) //後置--
{
Int Tmp(m_i);
this->m_i--;
return Tmp;
}
public:
int GetData()const
{
return this->m_i;
}
private:
long m_i;
};
int main()
{
Int a(1); //int a = 1; a++ ++a a-- --a
Int b(2);
cout << "a = " << a.GetData() << endl;
cout << "b = " << b.GetData() << endl;
Int result;
result = a + b; //result = 1 + 2;
cout << "result = " << result.GetData() << endl;
result = ++a;
result = a++;
return 0;
}
以上同類型的符号重載隻分析一種,因為+ - += -= * *= / /= % %= 都是一樣的邏輯,知一曉百
(1) +号的重載 有整數 a, b = 1, c = 2, d = 3 a = b + c + d; 上述加法要能正常執行就必須等号右邊每兩個數相加并傳回結果,計算順序是無關的 要先算出(b+c) = 3, 然後再算出來3 + d = 6 或者先算出來(c + d) = 5, 然後再算出來b + 5 = 6 最終将結果6傳回給a
有Test類的對象 a, b (1), c(2), d(3)
對象之間是無法直接相加的,是以需要運算符重載
對+号進行重載成類的成員函數如下:
a = b + c + d;
相當于:a = b + c.operator+(d); a = b.operator+( c.operator+(d) );
或: a = b.operator+© + d; a = ( b.operator+© ).operator+(d);
Int operator+(const Int& x)
{
return Int(this->m_i + x.m_i);
}
類的成員函數都是用對象來驅動的,被調用的成員方法的this指針便指向驅動它的對象
用this指針通路前對象的私有資料成員this->m_i,用常引用的形參const Int& x通路後對象的私有資料成員x.m_i,将資料相加然後構造一個臨時對象,傳回值按值傳回,便實作了将兩個對象相加,并将結果傳回,于是連續的對象相加也能實作
(2) +=重載 對象加等于a += b; 就是 a = a + b ; 單看a += b 則重載的+=是用對象a驅動的,a.operator+=(b); 最終隻有a的值發生了改變,是以b可以用常引用。對象a的生命不受重載的+=函數影響,是以a的值發生改變後可以引用傳回,以值的方式傳回也不會有任何問題。我們都知道函數參數按值傳回會借助臨時變量,由于是對象按值傳回,這樣的話就會多調用構造函數,即臨時變量占用了記憶體空間又調用了構造函數,導緻效率明顯降低了。 是以函數中不受函數控制生存周期的變量,強烈建議用引用傳回
Int& operator+=(const Int& x) // a += b;
{
this->m_i += x.m_i;
return *this;
}
(3) 以下右移位操作符>>和右移位等的操作符>>=重載和上面分析的+和+=是一樣的道理
Int operator>>(const Int& x) //a >> b
{
return Int(this->m_i >> x.m_i);
}
Int& operator>>=(const Int& x)
{
this->m_i >>= x.m_i;
return *this;
}
(4) ==操作符重載如下
bool operator==(const Int& x)
{
if (this->m_i == x.m_i)
return true;
return false;
}
覺得上述啰嗦吧,也可以如下的寫法:
但是上面的有更好的邏輯性,且傳回值類型比對都是布爾類型
bool operator==(const Int& x)
{
return (this->m_i == x.m_i)
}
(5) 前置++ 和後置++ 的重載
Int& operator++() //前置++ 比後置++ 效率 可以引用傳回
{
this->m_i++;
return *this;
}
Int operator++(int) //後置++
{
Int temp(*this); //調用拷貝構造函數或:
//Int tmp(this->m_i); //用構造函數
this->m_i++; //*this++
return temp;
}
前置++ 和後置++ 的重載,其實相當簡單,隻需要知道後置++ 要在函數清單設一個int就OK
前置++ ,是給對象先+1,然後以引用傳回
後置++ ,是先傳回對象,再給對象+1,錯錯錯,大錯特錯。再函數中一但傳回,函數就結束了,return後面的語句就不再執行了
正确的思路是先借助臨時變量記錄一下++的左值,然後給左值+1,然後按值傳回臨時變量(不能用引用傳回,語義上臨時變量不能用引用傳回,臨時變量一出作用 域就死亡了,死亡的東西就是未知的也許,那塊臨時空間還保留着出函數的值,恰巧結果可以正确,但未知和不确定的實物可能就是整個程式死亡的誘因,要嚴謹要嚴謹)。
二
模拟String類運算符重載
對于3中對模拟String類實作的剖析的例子,我們繼續對其進行運算符重載
實作友元函數:length()
重載以下運算符:
operator[]
operator+
operator+=
operator>
operator<
operator>=
operator<=
operator==
operator!=
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
#include<string.h>
using namespace std;
/
//length()
//operator[]
//operator+
//operator+=
//operator > < >= <= == !=
/
class String
{
public:
String(const char* str = "") //常類型到常類型
{
m_data = new char[strlen(str) + 1];
strcpy(m_data, str);
}
String(const String& s)
{
m_data = new char[strlen(s.m_data) + 1];
strcpy(m_data, s.m_data);
}
~String()
{
delete[]m_data;
m_data = NULL;
}
public:
size_t length()const
{
return strlen(m_data);
}
char operator[](int i)
{
assert(i >= 0 && i < length());
return m_data[i];
}
String& operator=(const String& s)
{
if (this != &s)
{
delete[](this->m_data);
//new char[s.length() + 1];
this->m_data = new char[s.length() + 1];
strcpy(this->m_data, s.m_data);
}
return *this;
}
String operator+(const String& s)
{
char* tmp = new char[length() + s.length() + 1]; //??????
strcpy(tmp, this->m_data);
strcat(tmp, s.m_data);
String temp(tmp);
delete []tmp;
return temp;
}
String& operator+=(const String& s)
{
char* tmp = new char[strlen(this->m_data) + strlen(s.m_data) + 1];
strcpy(tmp, this->m_data);
strcat(tmp, s.m_data);
delete[]m_data;
this->m_data = tmp;
return *this;
}
public:
bool operator==(const String& s)
{
if (strcmp(this->m_data, s.m_data) == 0)
return true;
return false;
}
bool operator!=(const String& s)
{
if (strcmp(this->m_data, s.m_data) != 0)
return true;
return false;
}
bool operator>(const String& s)
{
if (strcmp(this->m_data, s.m_data) > 0)
return true;
return false;
}
bool operator<(const String& s)
{
if (strcmp(this->m_data, s.m_data) < 0)
return true;
return false;
}
bool operator>=(const String& s)
{
if (strcmp(this->m_data, s.m_data) < 0)
return false;
return true;
}
bool operator<=(const String& s)
{
if (strcmp(this->m_data, s.m_data) > 0)
return false;
return true;
}
private:
char* m_data;
};
int main()
{
String s1("Hello"); //s1[0] ==> H
String s2("Bit.");
s1 = s2;
for (int i = 0; i < s1.length(); ++i)
cout << s1[i];
cout << endl;
String s = s1 + s2; //s = HelloBit
for (int i = 0; i < s.length(); ++i)
cout << s[i];
cout << endl;
s1 += s2; //
for (int i = 0; i < s1.length(); ++i)
cout << s1[i];
cout << endl;
return 0;
}
三
運算符重載之重載為成員函數:
下面的程式定義了一個簡單的SmallInt類,用來表示從-128到127之間的整數。
類的唯一的資料成員val存放一個-128到127(包含-128和127這兩個數)之間的整數,為了友善,
類SmallInt還重載了一些運算符。
閱讀SmallInt的定義,回答題目後面的問題。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class SmallInt;
ostream& operator<<(ostream& os, const SmallInt& si);
istream& operator>>(istream& is, SmallInt& si);
//SmallInt si(1000);
class SmallInt
{
public:
SmallInt(int i = 0);
//重載插入和抽取運算符
friend ostream& operator<<(ostream& os, const SmallInt& si);
friend istream& operator>>(istream& is, SmallInt& si);
//重載算術運算符
SmallInt operator+(const SmallInt& si) { return SmallInt(val + si.val); }
SmallInt operator-(const SmallInt& si) { return SmallInt(val - si.val); }
SmallInt operator*(const SmallInt& si) { return SmallInt(val * si.val); }
SmallInt operator/(const SmallInt& si) { return SmallInt(val / si.val); }
//重載比較運算符
bool operator==(const SmallInt& si) { return (val == si.val); }
private:
char val;
};
SmallInt::SmallInt(int i)
{
while (i > 127)
i -= 256;
while (i < -128)
i += 256;
val = i;
}
ostream& operator<<(ostream& os, const SmallInt& si)
{
os << (int)si.val;
return os;
}
istream& operator>>(istream& is, SmallInt& si)
{
int tmp;
is >> tmp;
si = SmallInt(tmp);
return is;
}
int main()
{
SmallInt si(1000);
cout << si << endl;
SmallInt si1;
cin >> si1;
cout << si1 << endl;
return 0;
}
問題:(本小題4分)上面的類定義中,
重載的插入運算符和抽取運算符被定義為類的友元函數?//可以
能不能将這兩個運算符定義為類的成員函數?//不能
如果能,寫出函數原型,如果不能,說明理由。
文法上可以,語義上不可以代碼如下:
///
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//SmallInt si(1000);
class SmallInt
{
public:
SmallInt(int i = 0);
//重載插入和抽取運算符
ostream& operator<<(ostream& os)
{
os << (int)this->val;
return os;
}
istream& operator>>(istream& is)
{
int tmp;
is >> tmp;
this->val = tmp;
return is;
}
//重載算術運算符
SmallInt operator+(const SmallInt& si) { return SmallInt(val + si.val); }
SmallInt operator-(const SmallInt& si) { return SmallInt(val - si.val); }
SmallInt operator*(const SmallInt& si) { return SmallInt(val * si.val); }
SmallInt operator/(const SmallInt& si) { return SmallInt(val / si.val); }
//重載比較運算符
bool operator==(const SmallInt& si) { return (val == si.val); }
private:
char val;
};
SmallInt::SmallInt(int i)
{
while (i > 127)
i -= 256;
while (i < -128)
i += 256;
val = i;
}
int main()
{
SmallInt si(1000);
si << cout << endl;
SmallInt si1;
si1 >> cin;
si1 << cout << endl;
return 0;
}
按題目要求重載,隻能像知識總結中一中的那種不符合使用習慣(使用就必須如下)的重載辦法
si << cout << endl;
si1 >> cin;
si1 << cout << endl;
重載為友元函數是可以的
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//SmallInt si(1000);
class SmallInt
{
public:
SmallInt(int i = 0);
//重載插入和抽取運算符
friend ostream& operator<<(ostream& os, const SmallInt& s);
friend istream& operator>>(istream& is, SmallInt& s);
//重載算術運算符
SmallInt operator+(const SmallInt& si) { return SmallInt(val + si.val); }
SmallInt operator-(const SmallInt& si) { return SmallInt(val - si.val); }
SmallInt operator*(const SmallInt& si) { return SmallInt(val * si.val); }
SmallInt operator/(const SmallInt& si) { return SmallInt(val / si.val); }
//重載比較運算符
bool operator==(const SmallInt& si) { return (val == si.val); }
private:
char val;
};
SmallInt::SmallInt(int i)
{
while (i > 127)
i -= 256;
while (i < -128)
i += 256;
val = i;
}
ostream& operator<<(ostream& os, const SmallInt& s)
{
os << s.val;
return os;
}
istream& operator>>(istream& is, SmallInt& s)
{
int tmp;
is >> tmp;
s.val = tmp;
return is;
}
int main()
{
SmallInt si(65);
SmallInt si1;
cout << si<<endl;
cin>>si1;
cout << si1 << endl;
return 0;
}
四
explicit關鍵字
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Test
{
public:
Test(int d = 0) : m_data(d) //構造函數的類型轉換(隐式)Test t1; t1 = 998;
{
m_count++;
}
~Test()
{
m_count--;
}
public:
int GetData()const
{return this->m_data;}
public:
operator int() //強制轉換
{
return this->m_data;
}
public:
void list()
{
fun();
}
static void fun()
{
m_count = 10;
cout<<"Test::fun() static"<<endl;
}
private:
int m_data;
static int m_count;
};
int Test::m_count = 0; //
int main()
{
Test t1;
t1 = 998;
return 0;
}
t1 = 998; //理論上我們知道普通變量是不能給對象指派的
但是實際上構造函數不僅可以構造對象還能夠隐式的做類型轉換,998給對象指派,會首先調用構造函數将整形998構造成一個匿名對象,然後用匿名對象去給對象t1指派。
如果我們給上述代碼的構造函數前加上explicit 關鍵字,構造函數便不能做隐式的類型轉化了
explicit Test(int d = 0) : m_data(d)
{
m_count++;
}
這樣寫編譯就無法通過如下圖:
五
啞成員
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Test
{
public:
Test(int d = 0) :m_data(d)
{}
public:
class Tmp //内部類
{
public:
Tmp(int a , int b) : x(a), y(b)
{}
public:
int GetX()
{return x;}
public:
int x; //
int y; //啞成員
};
public:
int m_data;
};
int main()
{
Test T;
cout <<"sizeof(T) = "<< sizeof(T) << endl;
Test::Tmp tp(1,2);
cout<<"sizeof(tp) = "<<sizeof(tp) << endl;
return 0;
}
内部類的資料成員稱為啞成員,因為執行個體的外部類對象的大小不包含内部類的大小,并且外部類中隻能通路自己的資料成員及函數成員,無法通路内部類的任何成員
建立類中類的對象時必須加外部類的作用域通路符:
Test::Tmp tp(1,2); //建立内部類Tmp的對象時就得加外部類Test的作用域通路符Test::
建立的外部類的對象大小不帶内部類