C++深入探究類與對象之友元與運算符重載
友元
生活中你的家有客廳(Public),有你的臥室(Private),客廳所有來的客人都可以進去,但是你的臥室是私有的,也就是說只有你能進去,但是呢,你也可以允許你的好閨蜜好基友進去。
在程序里,有些私有屬性也想讓類外特殊的一些函數或者類進行訪問,就需要用到友元的技術。
友元的目的就是讓一個函數或者類訪問另一個類中私有成員。
友元的關鍵字為: friend
友元的三種實現:
- 全局函數做友元
- 類做友元
- 成員函數做友元
1 全局函數做友元
class Building { //告訴編譯器 goodGay全局函數 是 Building類的好朋友,可以訪問類中的私有內容 friend void goodGay(Building * building); public: Building() { this->m_SittingRoom = "客廳"; this->m_BedRoom = "臥室"; } public: string m_SittingRoom; //客廳 private: string m_BedRoom; //臥室 }; void goodGay(Building * building) { cout << "好基友正在訪問: " << building->m_SittingRoom << endl; cout << "好基友正在訪問: " << building->m_BedRoom << endl; } void test01() { Building b; goodGay(&b); } int main(){ test01(); system("pause"); return 0; }
2 類做友元
class Building; class goodGay { public: goodGay(); void visit(); private: Building *building; }; class Building { //告訴編譯器 goodGay類是Building類的好朋友,可以訪問到Building類中私有內容 friend class goodGay; public: Building(); public: string m_SittingRoom; //客廳 private: string m_BedRoom;//臥室 }; Building::Building() { this->m_SittingRoom = "客廳"; this->m_BedRoom = "臥室"; } goodGay::goodGay() { building = new Building; } void goodGay::visit() { cout << "好基友正在訪問" << building->m_SittingRoom << endl; cout << "好基友正在訪問" << building->m_BedRoom << endl; } void test01() { goodGay gg; gg.visit(); } int main(){ test01(); system("pause"); return 0; }
3 成員函數做友元
class Building; class goodGay { public: goodGay(); void visit(); //只讓visit函數作為Building的好朋友,可以發(fā)訪問Building中私有內容 void visit2(); private: Building *building; }; class Building { //告訴編譯器 goodGay類中的visit成員函數 是Building好朋友,可以訪問私有內容 friend void goodGay::visit(); public: Building(); public: string m_SittingRoom; //客廳 private: string m_BedRoom;//臥室 }; Building::Building() { this->m_SittingRoom = "客廳"; this->m_BedRoom = "臥室"; } goodGay::goodGay() { building = new Building; } void goodGay::visit() { cout << "好基友正在訪問" << building->m_SittingRoom << endl; cout << "好基友正在訪問" << building->m_BedRoom << endl; } void goodGay::visit2() { cout << "好基友正在訪問" << building->m_SittingRoom << endl; //cout << "好基友正在訪問" << building->m_BedRoom << endl; } void test01() { goodGay gg; gg.visit(); } int main(){ test01(); system("pause"); return 0; }
運算符重載
運算符重載概念:對已有的運算符重新進行定義,賦予其另一種功能,以適應不同的數據類型
1 加號運算符重載
作用:實現兩個自定義數據類型相加的運算
class Person { public: Person() {}; Person(int a, int b) { this->m_A = a; this->m_B = b; } //成員函數實現 + 號運算符重載 Person operator+(const Person& p) { Person temp; temp.m_A = this->m_A + p.m_A; temp.m_B = this->m_B + p.m_B; return temp; } public: int m_A; int m_B; }; //全局函數實現 + 號運算符重載 //Person operator+(const Person& p1, const Person& p2) { // Person temp(0, 0); // temp.m_A = p1.m_A + p2.m_A; // temp.m_B = p1.m_B + p2.m_B; // return temp; //} //運算符重載 可以發(fā)生函數重載 Person operator+(const Person& p2, int val) { Person temp; temp.m_A = p2.m_A + val; temp.m_B = p2.m_B + val; return temp; } void test() { Person p1(10, 10); Person p2(20, 20); //成員函數方式 Person p3 = p2 + p1; //相當于 p2.operaor+(p1) cout << "mA:" << p3.m_A << " mB:" << p3.m_B << endl; Person p4 = p3 + 10; //相當于 operator+(p3,10) cout << "mA:" << p4.m_A << " mB:" << p4.m_B << endl; } int main() { test(); system("pause"); return 0; }
總結1:對于內置的數據類型的表達式的的運算符是不可能改變的
總結2:不要濫用運算符重載
2 左移運算符重載
作用:可以輸出自定義數據類型
class Person { friend ostream& operator<<(ostream& out, Person& p); public: Person(int a, int b) { this->m_A = a; this->m_B = b; } //成員函數 實現不了 p << cout 不是我們想要的效果 //void operator<<(Person& p){ //} private: int m_A; int m_B; }; //全局函數實現左移重載 //ostream對象只能有一個 ostream& operator<<(ostream& out, Person& p) { out << "a:" << p.m_A << " b:" << p.m_B; return out; } void test() { Person p1(10, 20); cout << p1 << "hello world" << endl; //鏈式編程 } int main() { test(); system("pause"); return 0; }
總結:重載左移運算符配合友元可以實現輸出自定義數據類型
3 遞增運算符重載
作用: 通過重載遞增運算符,實現自己的整型數據
class MyInteger { friend ostream& operator<<(ostream& out, MyInteger myint); public: MyInteger() { m_Num = 0; } //前置++ MyInteger& operator++() { //先++ m_Num++; //再返回 return *this; } //后置++ MyInteger operator++(int) { //先返回 MyInteger temp = *this; //記錄當前本身的值,然后讓本身的值加1,但是返回的是以前的值,達到先返回后++; m_Num++; return temp; } private: int m_Num; }; ostream& operator<<(ostream& out, MyInteger myint) { out << myint.m_Num; return out; } //前置++ 先++ 再返回 void test01() { MyInteger myInt; cout << ++myInt << endl; cout << myInt << endl; } //后置++ 先返回 再++ void test02() { MyInteger myInt; cout << myInt++ << endl; cout << myInt << endl; } int main() { test01(); //test02(); system("pause"); return 0; }
總結: 前置遞增返回引用,后置遞增返回值
4 賦值運算符重載
c++編譯器至少給一個類添加4個函數
- 默認構造函數(無參,函數體為空)
- 默認析構函數(無參,函數體為空)
- 默認拷貝構造函數,對屬性進行值拷貝
- 賦值運算符 operator=, 對屬性進行值拷貝
如果類中有屬性指向堆區(qū),做賦值操作時也會出現深淺拷貝問題
示例:
class Person { public: Person(int age) { //將年齡數據開辟到堆區(qū) m_Age = new int(age); } //重載賦值運算符 Person& operator=(Person &p) { if (m_Age != NULL) { delete m_Age; m_Age = NULL; } //編譯器提供的代碼是淺拷貝 //m_Age = p.m_Age; //提供深拷貝 解決淺拷貝的問題 m_Age = new int(*p.m_Age); //返回自身 return *this; } ~Person() { if (m_Age != NULL) { delete m_Age; m_Age = NULL; } } //年齡的指針 int *m_Age; }; void test01() { Person p1(18); Person p2(20); Person p3(30); p3 = p2 = p1; //賦值操作 cout << "p1的年齡為:" << *p1.m_Age << endl; cout << "p2的年齡為:" << *p2.m_Age << endl; cout << "p3的年齡為:" << *p3.m_Age << endl; } int main() { test01(); //int a = 10; //int b = 20; //int c = 30; //c = b = a; //cout << "a = " << a << endl; //cout << "b = " << b << endl; //cout << "c = " << c << endl; system("pause"); return 0; }
5 關系運算符重載
**作用:**重載關系運算符,可以讓兩個自定義類型對象進行對比操作
示例:
class Person { public: Person(string name, int age) { this->m_Name = name; this->m_Age = age; }; bool operator==(Person & p) { if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) { return true; } else { return false; } } bool operator!=(Person & p) { if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) { return false; } else { return true; } } string m_Name; int m_Age; }; void test01() { //int a = 0; //int b = 0; Person a("孫悟空", 18); Person b("孫悟空", 18); if (a == b) { cout << "a和b相等" << endl; } else { cout << "a和b不相等" << endl; } if (a != b) { cout << "a和b不相等" << endl; } else { cout << "a和b相等" << endl; } } int main() { test01(); system("pause"); return 0; }
6 函數調用運算符重載
- 函數調用運算符 () 也可以重載
- 由于重載后使用的方式非常像函數的調用,因此稱為仿函數
- 仿函數沒有固定寫法,非常靈活
示例:
class MyPrint { public: void operator()(string text) { cout << text << endl; } }; void test01() { //重載的()操作符 也稱為仿函數 MyPrint myFunc; myFunc("hello world"); } class MyAdd { public: int operator()(int v1, int v2) { return v1 + v2; } }; void test02() { MyAdd add; int ret = add(10, 10); cout << "ret = " << ret << endl; //匿名對象調用 cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl; } int main() { test01(); test02(); system("pause"); return 0; }
到此這篇關于C++深入探究類與對象之友元與運算符重載的文章就介紹到這了,更多相關C++友元內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
VisualStudio?禁用移動文件到文件夾自動修改命名空間功能
這篇文章主要介紹了VisualStudio?禁用移動文件到文件夾自動修改命名空間功能,文章底部給大家介紹了解決安裝VS2022時,出現未能安裝包“Microsoft.VisualCpp.Redist.14,version=14.32.31332,chip”=x86,的問題及解決方法,需要的朋友可以參考下2022-09-09