友元
友元函數(shù)
友元函數(shù)是定義在類外部,但有權(quán)訪問(wèn)類的所有私有(private)成員和保護(hù)(protected)成員。盡管友元函數(shù)的原型有在類的定義中出現(xiàn)過(guò),但是友元函數(shù)并不是成員函數(shù)。
關(guān)鍵字friend
friend 返回值類型 函數(shù)名(參數(shù)列表);
friend void global_printf(Point const that); //友元函數(shù)
友元類
友元類的所有成員函數(shù)都是另一個(gè)類的友元函數(shù),都可以訪問(wèn)另一個(gè)類中的隱藏信息(包括私有成員和保護(hù)成員)
//類前面加上friend聲明友元類
class Point
{
int m_x;
int m_y;
public:
friend class Point3D;//友元類
};
class Point3D
{
Point m_p;
int m_z;
public:
};
注意事項(xiàng):
- 只有友元可以訪問(wèn),其他依然不能訪問(wèn)。
若類B是類A的友元。則只有類B的成員函數(shù)可以訪問(wèn)類A中的隱藏信息
- 友元是單向的,不具有交換性。
若類B是類A的友元,類A不一定是類B的友元,要看在類中是否有相應(yīng)的聲明。
- 友元關(guān)系不具有傳遞性。
若類B是類A的友元,類C是B的友元,類C不一定是類A的友元,同樣要看類中是否有相應(yīng)的申明
友元類以及友元函數(shù)示例程序
//demo1.cpp
#include<iostream>
using namespace std;
class Point
{
int m_x;
int m_y;
public:
Point(int x = 0, int y = 0); //缺省構(gòu)造函數(shù) 類內(nèi)聲明類外定義
void Point_printf(); //類內(nèi)數(shù)據(jù)打印函數(shù)
friend void global_printf(Point const that); //友元函數(shù) 類外數(shù)據(jù)打印函數(shù)
friend class Point3D; //友元類
};
class Point3D
{
Point m_p;
int m_z;
public:
Point3D(int x = 0, int y = 0, int z = 0);
void Point3D_printf();
};
int main()
{
Point point(10,20);
cout << "========類函數(shù)打印========" << endl;
point.Point_printf();
cout << "========友元函數(shù)打印========" << endl;
global_printf(point);
cout << "========友元類打印========" << endl;
Point3D point3d(10, 20, 30);
point3d.Point3D_printf();
cin.get();
return 0;
}
Point::Point(int x, int y)
{
m_x = x;
m_y = y;
}
void Point::Point_printf()
{
cout << this->m_x << " " << this->m_y << endl;
}
void global_printf(Point const that)
{
cout << that.m_x << " " << that.m_y << endl;
}
Point3D::Point3D(int x, int y, int z)
{
m_p.m_x = x;
m_p.m_y = y;
m_z = z;
}
void Point3D::Point3D_printf()
{
cout << m_p.m_x << " " << m_p.m_y << " " << m_z << endl;
}
打印結(jié)果:
========類函數(shù)打印========
10 20
========友元函數(shù)打印========
10 20
========友元類打印========
10 20 30
運(yùn)算符重載
運(yùn)算符重載,就是對(duì)已有的運(yùn)算符重新進(jìn)行定義,賦予其另一種功能,以適應(yīng)不同的數(shù)據(jù)類型。
重載運(yùn)算符可以使用成員函數(shù)或非成員函數(shù)(一般是友元函數(shù))兩種方法
只能使用其中的一種方法
關(guān)鍵字operator
類名 operator運(yùn)算符(const 類名& other);//成員函數(shù)實(shí)現(xiàn)
Complex operator+(const Complex& other);
可重載運(yùn)算符
| 雙目算術(shù)運(yùn)算符 | + (加),-(減),*(乘),/(除),% (取模) |
|---|---|
| 關(guān)系運(yùn)算符 | ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于) |
| 邏輯運(yùn)算符 | ||(邏輯或),&&(邏輯與),!(邏輯非) |
| 單目運(yùn)算符 | + (正),-(負(fù)),*(指針),&(取地址) |
| 自增自減運(yùn)算符 | ++(自增),--(自減) |
| 位運(yùn)算符 | | (按位或),& (按位與),~(按位取反),^(按位異或),,<< (左移),>>(右移) |
| 賦值運(yùn)算符 | =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>= |
| 空間申請(qǐng)與釋放 | new, delete, new[ ] , delete[] |
| 其他運(yùn)算符 | ()(函數(shù)調(diào)用),->(成員訪問(wèn)),,(逗號(hào)),[](下標(biāo)) |
不可重載的運(yùn)算符
- .:成員訪問(wèn)運(yùn)算符
- .*, ->*:成員指針訪問(wèn)運(yùn)算符
- :::域運(yùn)算符
- sizeof:長(zhǎng)度運(yùn)算符
- ?::條件運(yùn)算符
- #: 預(yù)處理符號(hào)
運(yùn)算符重載注意事項(xiàng)
- 運(yùn)算重載符不可以改變語(yǔ)法結(jié)構(gòu)
- 運(yùn)算重載符不可以改變操作數(shù)的個(gè)數(shù)
- 運(yùn)算重載符不可以改變優(yōu)先級(jí)
- 運(yùn)算重載符不可以改變結(jié)合性
- 不能創(chuàng)建新的運(yùn)算符
+,- 運(yùn)算符重載
Complex operator+(const Complex& other);//+運(yùn)算符重載 成員函數(shù)實(shí)現(xiàn)
friend Complex operator-(const Complex&A, const Complex&B);//-運(yùn)算符重載 非成員函數(shù)實(shí)現(xiàn)
=賦值運(yùn)算符重載
如果沒(méi)有重載賦值運(yùn)算符,操作系統(tǒng)會(huì)有缺省運(yùn)算符重載,編譯器提供的默認(rèn)拷貝賦值操作符重載,同默認(rèn)拷貝構(gòu)造一樣,默認(rèn)拷貝賦值操作符重載同樣是淺拷貝。
Complex operator=(const Complex&other); //=運(yùn)算符重載 成員函數(shù)實(shí)現(xiàn)
注意事項(xiàng)
- 避免自賦值
- 釋放舊資源
- 分配新資源
- 拷貝新內(nèi)容
- 返回自引用
//為了簡(jiǎn)便,只實(shí)現(xiàn)=運(yùn)算符的避免自賦值,更多請(qǐng)看string類
Complex operator=(const Complex&other)
{
if (&other != this) //防止自賦值
{
m_real = other.m_real;
m_imaginary = other.m_imaginary;
}
return *this;
}
前++,后++運(yùn)算符重載
Complex operator++(); //前++運(yùn)算符重載 成員函數(shù)實(shí)現(xiàn)
Complex operator++(int); //后++運(yùn)算符重載通過(guò)啞元實(shí)現(xiàn) 成員函數(shù)實(shí)現(xiàn)
流操作符>>,<<重載
cout是輸出類的對(duì)象,而cin是輸入類的對(duì)象,C++頭文件iostream取自istream和ostream之意
流操作符>>,<<一般使用非成員函數(shù)實(shí)現(xiàn),也就是友元函數(shù)實(shí)現(xiàn),這樣可以符合程序員的慣性思維
friend ostream &operator<<(ostream &os, const Complex&other);//IO流運(yùn)算符重載函數(shù)一般聲明為類的友元函數(shù)
friend istream &operator >> (istream &is, Complex&other); //類的非成員函數(shù)重載>>提取運(yùn)算符
讓我們來(lái)看一下如果使用類成員方法重載流操作運(yùn)算符會(huì)怎樣一個(gè)結(jié)果
istream &operator>>(istream &is); //類的成員函數(shù)重載>>提取運(yùn)算符
這樣定義的話使用的時(shí)候
Complex test;
test >> cin; //類的成員函數(shù)提取運(yùn)算符的調(diào)用
跟自己使用cin不太一樣對(duì)不對(duì),就像一個(gè)反人類的設(shè)計(jì)..
運(yùn)算符重載示例程序1
//demo_2.cpp
#include<iostream>
using namespace std;
#define IS_MEMBER 0
class Complex
{
double m_real;
double m_imaginary;
public:
Complex(double r = 0, double i = 0);
void Complex_show();
Complex operator+(const Complex& other); //+運(yùn)算符重載 成員函數(shù)實(shí)現(xiàn)
Complex operator=(const Complex&other); //=運(yùn)算符重載 成員函數(shù)實(shí)現(xiàn)
Complex operator++(); //前++運(yùn)算符重載 成員函數(shù)實(shí)現(xiàn)
Complex operator++(int); //后++運(yùn)算符重載 成員函數(shù)實(shí)現(xiàn)
friend Complex operator-(const Complex&A, const Complex&B); //-運(yùn)算符重載 非成員函數(shù)實(shí)現(xiàn)
friend ostream &operator<<(ostream &os, const Complex&other);//IO流運(yùn)算符重載函數(shù)一般聲明為類的友元函數(shù)
#if IS_MENBER
istream &operator>>(istream &is); //類的成員函數(shù)重載>>提取運(yùn)算符
#else
friend istream &operator >> (istream &is, Complex&other); //類的非成員函數(shù)重載>>提取運(yùn)算符
#endif
};
int main()
{
Complex complex_1(1, 8), complex_2(2, 5), temp;
cout << "===========+操作符重載===========" << endl;
temp = complex_1 + complex_2;
temp.Complex_show();
cout << "===========流操作符重載===========" << endl;
Complex test;
#if IS_MENBER
test >> cin; //類的成員函數(shù)提取運(yùn)算符的調(diào)用
#else
cin >> test;
#endif
complex_1 = test;
cout << "===========-操作符重載===========" << endl;
temp = complex_1 - complex_2;
cout <<"temp:"<< temp << endl;
cout << "============前++后++==========" << endl;
Complex complex_3(1, 1);
cout << complex_3++;
cout << complex_3;
cout << ++complex_3;
cin.get();
cin.get();
return 0;
}
Complex::Complex(double r, double i)
{
m_real = r;
m_imaginary = i;
}
void Complex::Complex_show()
{
cout << m_real << "+" << m_imaginary << "i" << endl;
}
Complex Complex::operator+(const Complex & other)
{
Complex temp;
temp.m_real = this->m_real + other.m_real;
temp.m_imaginary = this->m_imaginary + other.m_imaginary;
return temp;
}
Complex Complex::operator=(const Complex & other)
{
if (&other != this)
{
m_real = other.m_real;
m_imaginary = other.m_imaginary;
}
return *this;
}
Complex Complex::operator++()
{
this->m_real = this->m_real + 1;
return *this;
}
Complex Complex::operator++(int)
{
Complex temp = *this;
this->m_real = this->m_real + 1;
return temp;
}
#if IS_MENBER
istream & Complex::operator >> (istream & is)
{
cin >> this->m_real >> this->m_imaginary;
// TODO: 在此處插入 return 語(yǔ)句
return is;
}
#else
istream & operator >> (istream & is, Complex & other)
{
is >> other.m_real >> other.m_imaginary;
// TODO: 在此處插入 return 語(yǔ)句
return is;
}
#endif
Complex operator-(const Complex & A, const Complex & B)
{
Complex temp;
temp.m_real = A.m_real - B.m_real;
temp.m_imaginary = A.m_imaginary - B.m_imaginary;
return temp;
}
ostream & operator<<(ostream & os, const Complex & other)
{
os << other.m_real << "+" << other.m_imaginary << "i" << " ";
// TODO: 在此處插入 return 語(yǔ)句
return os;
}
//運(yùn)行結(jié)果
===========+操作符重載===========
3+13i
===========流操作符重載===========
4 5
===========-操作符重載===========
temp:2+0i
============前++后++==========
1+1i 2+1i 3+1i
new,delete重載
//類內(nèi)實(shí)現(xiàn)new運(yùn)算符重載 new的返回值必須是void* 第一個(gè)參數(shù)必須為size_t
void* operator new(size_t size);//類的非成員函數(shù)重載new
//類內(nèi)實(shí)現(xiàn)new運(yùn)算符重載 new的返回值必須是void* 第一個(gè)參數(shù)必須為void*
void operator delete(void* ptr);//類的非成員函數(shù)重載delete
注意:對(duì)于new的重載返回值必須是void*;delete的重載返回值一定是void
運(yùn)算符重載示例程序2
//demo_3.cpp
#include<iostream>
using namespace std;
class Integer
{
char* m_str;
int m_len;
public:
Integer()
{
m_len = 1;
m_str = new char[m_len];
m_str[0] = '\0';
}
Integer(const char* str)
{
m_len = strlen(str) + 1; //這個(gè)1留給\0
m_str = new char[m_len];
strcpy(m_str, str);
}
char & operator[](int i);
//類內(nèi)實(shí)現(xiàn)new運(yùn)算符重載 new的返回值必須是void* 第一個(gè)參數(shù)必須為size_t
void* operator new(size_t size)
{
return (Integer*)malloc(size);
}
//類內(nèi)實(shí)現(xiàn)new運(yùn)算符重載 new的返回值必須是void* 第一個(gè)參數(shù)必須為void*
void operator delete(void* ptr)
{
free(ptr);
}
friend ostream &operator<<(ostream &os, const Integer&other);
};
int main()
{
Integer* arr = new Integer("hello world!");
cout << *arr << endl;
Integer str("hello C++!");
for (int i = 0; i <= 10; i++)
{
cout << str[i];
}
delete arr;
cin.get();
return 0;
}
ostream & operator<<(ostream & os, const Integer & other)
{
cout << other.m_str;
// TODO: 在此處插入 return 語(yǔ)句
return os;
}
char & Integer::operator[](int i)
{
//TODO: 在此處插入 return 語(yǔ)句
return m_str[i];
}
//運(yùn)行結(jié)果
hello world!
hello C++!