類和對象2

三、C++對象模型和this指針

3.1?成員變量和成員函數分開存儲

在C++中,類內的成員變量和成員函數分開存儲,只有非靜態成員變量才屬于類的對象上

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Person {int m_A;//非靜態成員變量屬于類的對象上static int m_B;//靜態成員變量不屬于類的對象上void func() {}//非靜態成員函數不屬于類的對象上static void func2() {}//靜態成員函數不屬于類的對象上
};int Person::m_B = 10;void test01() {Person p;//空對象占用內存空間為 1 個字節//C++編譯器會給每個空對象也分配一個字節空間,是為了區分空對象占內存的位置//每個空對象也有一個獨一無二的內存地址cout << "size of p = " << sizeof(p) << endl;
}
void test02() {Person p;//占用內存空間為 4 個字節cout << "size of p = " << sizeof(p) << endl;
}int main() {//test01();test02();system("pause");return 0;
}

3.2 this指針概念

通過上面我們知道在C++中成員變量和成員函數是分開存儲的,每一個非靜態成員函數只會誕生一份函數實例,也就是說多個同類型的對象會共用一塊代碼那么問題是:這—塊代碼是如何區分那個對象調用自己的呢?

C++通過提供特殊的對象指針, this指針,解決上述問題的。this指針指向被調用的成員函數所屬的對象

this指針是隱含每一個非靜態成員函數內的一種指針

this指針不需要定義,直接使用即可

this指針的用途:

1.當形參和成員變量同名時,可用this指針來區分

2.·當形參和成員變量同名時,可用this指針來區分

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Person {
public:Person(int age) {//age = age;這樣寫無法區分,達到所需要求//this指針指向的是 被調用的成員函數所屬的對象 即p1this->age = age;}Person& PersonAddAge(Person &p) {this->age += p.age;//this指向p2的指針,而*this指向的就是p2,返回本體用&//如果去掉&,就是返回值,答案為20,出來的是p2'一個新的對象return *this;}//解決名稱沖突int age;};void test01() {Person p1(18);cout << "p1的年齡為:" << p1.age << endl;}

3.3 空指針訪問成員函數

C++中空指針也是可以調用成員函數的,但是也要注意有沒有用到this指針

如果用到this指針,需要加以判斷保證代碼的健壯性

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Person {
public:void showClassName() {cout << "this is Person class" << endl;}void showPersonAge() {if (this == NULL) {return;}cout << "age = " << this->m_Age << endl;}int m_Age;};void test01() {Person* p = NULL;p->showClassName();//在新版VS里雖然能運行,但是仍存在問題,傳入的指針為空p->showPersonAge();
}int main() {test01();system("pause");return 0;
}

3.4 const修飾成員函數

常函數:

·成員函數后加const后我們稱為這個函數為常函數

·常函數內不可以修改成員屬性

·成員屬性聲明時加關鍵字mutable后,在常函數中依然可以修改

常對象:

·聲明對象前加const稱該對象為常對象

·常對象只能調用常函數

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Person {
public://常函數//this指針的本質 是指針常量 指針的指向是不可修改的//const Person * const this;//Person * const this 就是this在成員函數后面加const,修飾的是this指向,讓指針指向的值也不可以修改void showPerson() const{//加上const則值也不可修改//this->m_A = 100; 報錯//this = NULL; 已經指向 p,不可修改this->m_B = 100;}void func(){}int m_A;mutable int m_B;//特殊變量,即使在常函數中,也可以修改這個值
};void test01() {Person p;p.showPerson();
}//常對象
void test02() {const Person p;//在對象前加上const//p.m_A = 100;不可修改p.m_B = 100;//m_B是特殊的值,在常對象下也可修改//常對象只能調用常函數//p.func();不可調用普通的成員函數,因為普通的成員函數可以修改
}int main() {test01();test02();system("pause");return 0;
}

四、友元

生活中你的家有客廳(Public),有你的臥室(Private。客廳所有來的客人都可以進去,但是你的臥室是私有的,也就是說只有你能進去但是呢,你也可以允許你的好閨蜜好基友進去。

在程序里,有些私有屬性也想讓類外特殊的一些函數或者類進行訪問,就需要用到友元.

友元的目的就是讓—個函數或者類訪問另—個類中私有成員.

友元的關鍵字為friend

友元的三種實現:

·全局函數做友元

·類做友元

·成員函數做友元

4.1?全局函數做友元

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Buliding {//這樣就可以使其函數訪問私有成員friend void goodGay(Buliding* bulidding);
public:Buliding() {m_SittingRoom = "客廳";m_BedRoom = "臥室";}public:string m_SittingRoom;//客廳
private:string m_BedRoom;//臥室};void goodGay(Buliding *bulidding) {cout << "好基友的全局函數 正在訪問:" << bulidding->m_SittingRoom << endl;cout << "好基友的全局函數 正在訪問:" << bulidding->m_BedRoom << endl;
}void test01() {Buliding bulidding;goodGay(&bulidding);}int main() {test01();system("pause");return 0;
}

4.2 類做友元

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Building;
class GoodGay {
public:GoodGay();void visit();Building * building;
};class Building {//這樣GoodGay類的成員就可以訪問本類的私有成員friend class GoodGay;
public:Building();public:string m_SittingRoom;//客廳
private:string m_BedRoom;//臥室};Building::Building() {m_SittingRoom = "客廳";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;
}

4.3 成員函數做友元

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Building;
class GoodGay {
public:GoodGay();void visit();//讓visit函數可以訪問Building中私有成員void visit2();//讓visit2函數不可以訪問Building中私有成員Building * building;
};class Building {//告訴編譯器GoodGay類下的visit成員函數作為本類的好朋友,可以訪問私有成員friend void GoodGay::visit();
public:Building();public:string m_SittingRoom;//客廳
private:string m_BedRoom;//臥室};Building::Building() {m_SittingRoom = "客廳";m_BedRoom = "臥室";
}GoodGay::GoodGay() {building = new Building;
}void GoodGay::visit() {cout << "visit 函數正在訪問:" << building->m_SittingRoom << endl;cout << "visit 函數正在訪問:" << building->m_BedRoom << endl;
}void GoodGay::visit2() {cout << "visit2 函數正在訪問:" << building->m_SittingRoom << endl;//會報錯//cout << "visit2 函數正在訪問:" << building->m_BedRoom << endl;
}void test01() {GoodGay gg;gg.visit();gg.visit2();
}int main() {test01();system("pause");return 0;
}

五、運算符重載

運算符重載概念:對已有的運算符重新進行定義,賦予其另一種功能,以適應不同的數據類型

5.1 加號運算符重載

作用:實現兩個自定義數據類型相加的運算

eg.

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;//加號運算符重載
class Person {public://1、成員函數重載 + 號成員函數重載本質調用//Person p3 = p1.operator+(p2);/*Person operator+(Person& p) {Person temp;temp.m_A = this->m_A + p.m_A;temp.m_B = this->m_B + p.m_B;return temp;}*/int m_A;int m_B;
};//2、全局函數重載 + 號
//全局函數重載本質調用
// Person p3 = operator+(p1, p2);
Person operator+(Person& p1, Person& p2) {Person temp;temp.m_A = p1.m_A + p2.m_A;temp.m_B = p1.m_B + p2.m_B;return temp;
}//函數重載的版本
Person operator+(Person& p1, int num) {Person temp;temp.m_A = p1.m_A + num;temp.m_B = p1.m_B + num;return temp;
}void test01() {Person p1;p1.m_A = 10;p1.m_B = 10;Person p2;p2.m_A = 10;p2.m_B = 10;Person p3;p3 = p1 + p2;//運算符重載`也可以發生函數重載Person p4 = p1 + 100;cout << "p3.m_A = " << p3.m_A << endl;cout << "p3.m_B = " << p3.m_B << endl;cout << "p4.m_A = " << p4.m_A << endl;cout << "p4.m_B = " << p4.m_B << endl;
}int main() {test01();system("pause");return 0;
}

注意:

1: 對于內置的數據類型的表達式的的運算符是不可能改變的

2: 不要濫用運算符重載

5.2 左移運算符<<重載(較難)

作用:可以輸出自定義數據類型

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;//左移運算符重載
class Person {public://利用成員函數重載左移運算符//不會利用成員函數重載<<運算符,因為無法實現cout在左側//void operator<<(Person &p) {//	//兩個對象了//	//改為p.operator<<(cout) 簡化版本 p << cout//}int m_A;int m_B;
};///只能利用全局函數重載左移運算符ostream& operator<<(ostream &cout,Person p)//本質operator<< ( cout ,p )簡化 cout<< p 
{//全局只能有1個,所以用&coutcout << "m_A = " << p.m_A << " m_B = " << p.m_B;return cout;
}void test01() {Person p;p.m_A = 10;p.m_B = 10;cout << p << "hello,word" << endl;
}int main() {test01();system("pause");return 0;
}

5.3 遞增運算符重載

作用:通過重載遞增運算符,實現自己的整型數據

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;//重載遞增運算符//自定義整型
class MyInteger {friend ostream& operator<<(ostream& cout, MyInteger myint);
public:MyInteger() {m_Num = 0;}//重載前置++運算符,返回引用為了一直對一個數據講行遞增操作MyInteger& operator++() {m_Num++;return *this;}//重載后置++運算符//void operator++(int) int代表占位參數,可以用于區分前置和后置MyInteger operator++(int) {//先記錄當時結果MyInteger temp = *this;//后遞增m_Num++;//最后將記錄結果做返回return temp;}
private:int m_Num;};ostream& operator<<(ostream& cout, MyInteger myint) {cout << myint.m_Num;return cout;
}void test01() {MyInteger myint;cout << ++(++myint) << endl;
}
void test02() {MyInteger myint;cout << myint++ << endl;cout << myint << endl;
}int main() {test01();test02();system("pause");return 0;
}

5.4 賦值運算符重載

C++編譯器至少給一個類添加4個函數

1.默認構造函數(無參,函數體為空)

2.默認析構函數(無參,函數體為空)

3.默認拷貝構造函數,對屬性進行值拷貝

4.賦值運算符operator=,對屬性進行值拷貝

如果類中有屬性指向堆區,做賦值操作時也會出現深淺拷貝問題

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;//重載賦值運算符
class Person {
public:Person(int age) {m_Age = new int(age);}~Person() {if (m_Age != NULL) {delete(m_Age);m_Age = NULL;}}Person& operator=(Person& p) {//應該先判斷是否有屬性在堆區,如果有先釋放干凈,然后再深拷貝if (m_Age != NULL) {delete m_Age;m_Age = NULL;}this->m_Age = new int(*p.m_Age);return *this;}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();system("pause");return 0;
}

5.5 關系運算符重載

作用:重載關系運算符,可以讓兩個自定義類型對象進行對比操作

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;//重載關系運算符class Person {
public:Person(string name,int age) {m_Name = name;m_Age = age;}//重載==號bool operator==(Person &p) {if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) {return true;}return false;}bool operator!=(Person& p) {if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) {return false;}return true;}string m_Name;int m_Age;
};void test01() {Person p1("Tom", 18);Person p2("Tom", 8);if (p1 == p2) {cout << "p1和p2是相等的!" << endl;}else {cout << "p1和p2是不相等的!" << endl;}if (p1 != p2) {cout << "p1和p2是不相等的!" << endl;}else {cout << "p1和p2是相等的!" << endl;}}int main() {test01();system("pause");return 0;
}

5.6 函數調用運算符()重載

·函數調用運算符()也可以重載

·由于重載后使用的方式非常像函數的調用,因此稱為仿函數

·仿函數沒有固定寫法,非常靈活

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;//重載函數調用運算符
class MyPrint {
public://重載函數調用運算符void operator()(string test) {cout << test << endl;}
};void test02(string test) {cout << test << endl;}void test01() {MyPrint myPrint;myPrint("hello world!");//由于使用起來非常類似于函數調用,因此稱為仿函數test02("hello world!");
}//仿函數沒有固定寫法,非常靈活
//加法類class MyAdd {
public:int operator()(int num1, int num2) {return num1 + num2;}};void test03() {MyAdd myAdd;int ret = myAdd(100, 100);cout << "ret = " << ret << endl;//匿名函數對象cout << MyAdd()(100, 100) << endl;
}int main() {test01();test03();system("pause");return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/16072.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/16072.shtml
英文地址,請注明出處:http://en.pswp.cn/web/16072.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux系統之GoAccess實時Web日志分析工具的基本使用

Linux系統之GoAccess實時Web日志分析工具的基本使用 一、GoAccess介紹1.1 GoAccess簡介1.2 GoAccess功能1.3 Web日志格式 二、本地環境介紹2.1 本地環境規劃2.2 本次實踐介紹 三、檢查本地環境3.1 檢查本地操作系統版本3.2 檢查系統內核版本3.3 檢查系統鏡像源3.4 更新軟件列表…

JavaFX安裝與使用

前言 最近學習了javafx,開始時在配置環境和導包時遇到了一些麻煩,關于網上很多方法都嘗試過了,現在問題都解決了,和大家分享一下我是怎么實現javafx的配置,希望大家可以通過這個方法實現自己的環境配置! &#x1f648;個人主頁: 心.c &#x1f525;文章專題:javafx &#x1f49…

如何在linux命令行(終端)執行ipynb 文件。可以不依賴jupyter

1.安裝 runipy pip install runipy 2.終端運行 runipy <YourNotebookName>.ipynb 在終端命令行執行shell腳本&#xff0c;&#xff08;也可以在crontab 中執行&#xff09;&#xff1a; (base) [recommendapp-0-5-B-006 script]$ cat run1.sh #!/bin/bashcd /home/recom…

計算機網絡-Traffic-Filter流量過濾策略

一、概述 為提高網絡安全性&#xff0c;管理人員需要控制進入網絡的流量&#xff0c;將不信任的報文丟棄在網絡邊界。所謂的不信任報文是指對用戶來說存在安全隱患或者不愿意接收的報文。同時保證數據訪問安全性&#xff0c;企業網絡中經常會要求一些部門之間不能相互訪問。 背…

服務器數據恢復—同友存儲raid5陣列上層虛擬機數據恢復案例

服務器數據恢復環境&#xff1a; 某市教育局同友存儲&#xff0c;存儲中有一組由數塊磁盤組建的raid5陣列&#xff0c;存儲空間劃分若干lun。每個lun中有若干臺虛擬機&#xff0c;其中有數臺linux操作系統的虛擬機為重要數據。 存儲結構&#xff1a; 服務器故障&#xff1a; r…

前端面試個人技能總結

1.html5新特性 語義化標簽&#xff1a;header footer nav section artical aside媒體標簽&#xff1a;qudio video &#xff08;control autoplay loop &#xff09; source標簽表單新增屬性&#xff1a;輸入類型type:email url data month week color&#xff1b;新增屬性&…

slam14講(第9,10講 后端)

slam14講&#xff08;第9&#xff0c;10講 后端&#xff09; 后端分類基于濾波器的后端線性系統和卡爾曼濾波非線性系統和擴展卡爾曼濾波 BA優化H矩陣的稀疏性和邊緣化H矩陣求解的總結 位姿圖優化公式推導 基于滑動窗口的后端個人見解舊關鍵幀的邊緣化 后端分類 基于濾波器的后…

AtCoder Beginner Contest 355 A~F

A.Who Ate the Cake?(思維) 題意 已知有三個嫌疑人&#xff0c;有兩個證人&#xff0c;每個證人可以指出其中一個嫌疑人不是罪犯&#xff0c;如果可以排除兩個嫌疑人來確定犯人&#xff0c;輸出犯人的身份&#xff0c;如果無法確定&#xff0c;輸出"-1"。 分析 …

AT_abc351_c [ABC351C] Merge the balls 題解

題目傳送門 題目大意 你有一個空序列和 N N N 個球。第 i i i 個球 ( 1 ≤ i ≤ N ) (1 \leq i \leq N) (1≤i≤N) 的大小是 2 A i 2^{A_i} 2Ai?。 計算 N N N 操作后序列中剩余的球的個數。 你將進行 N N N 次運算。 在第 i i i 次操作中&#xff0c;你將第 i i…

springboot + Vue前后端項目(第十一記)

項目實戰第十一記 1.寫在前面2. 文件上傳和下載后端2.1 數據庫編寫2.2 工具類CodeGenerator生成代碼2.2.1 FileController2.2.2 application.yml2.2.3 攔截器InterceptorConfig 放行 3 文件上傳和下載前端3.1 File.vue頁面編寫3.2 路由配置3.3 Aside.vue 最終效果圖總結寫在最后…

TabAttention:基于表格數據的條件注意力學習

文章目錄 TabAttention: Learning Attention Conditionally on Tabular Data摘要方法實驗結果 TabAttention: Learning Attention Conditionally on Tabular Data 摘要 醫療數據分析通常結合成像數據和表格數據處理&#xff0c;使用機器學習算法。盡管先前的研究探討了注意力…

Hudi 多表攝取工具 HoodieMultiTableStreamer 配置方法與示例

博主歷時三年精心創作的《大數據平臺架構與原型實現&#xff1a;數據中臺建設實戰》一書現已由知名IT圖書品牌電子工業出版社博文視點出版發行&#xff0c;點擊《重磅推薦&#xff1a;建大數據平臺太難了&#xff01;給我發個工程原型吧&#xff01;》了解圖書詳情&#xff0c;…

vue3添加收藏網站頁面

結構與樣式 <template><div class"web_view"><ul><li v-for"web in webList" :key"web.title"><a :href"web.src" :title"web.title" target"_blank"><img :src"web.img&…

微信小程序基礎 -- 小程序UI組件(5)

小程序UI組件 1.小程序UI組件概述 開發文檔&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/framework/view/component.html 什么是組件&#xff1a; 組件是視圖層的基本組成單元。 組件自帶一些功能與微信風格一致的樣式。 一個組件通常包括 開始標簽 和 結…

Cyber Weekly #8

賽博新聞 1、微軟召開年度發布會Microsoft Build 2024 本周&#xff08;5.22&#xff09;微軟召開了年度發布會&#xff0c;Microsoft Build 2024&#xff0c;發布了包括大殺器 Copilot Studio 在內的 50 項更新。主要包括&#xff1a; 硬件層面&#xff1a;與英偉達 & A…

3D牙科網格分割使用基于語義的特征學習與圖變換器

文章目錄 3D Dental Mesh Segmentation Using Semantics-Based Feature Learning with Graph-Transformer摘要方法實驗結果 3D Dental Mesh Segmentation Using Semantics-Based Feature Learning with Graph-Transformer 摘要 本文提出了一種新穎的基于語義的牙科網格分割方…

民國漫畫雜志《時代漫畫》第16期.PDF

時代漫畫16.PDF: https://url03.ctfile.com/f/1779803-1248612470-6a05f0?p9586 (訪問密碼: 9586) 《時代漫畫》的雜志在1934年誕生了&#xff0c;截止1937年6月戰爭來臨被迫停刊共發行了39期。 ps:資源來源網絡&#xff01;

代碼隨想錄訓練營總結

歷經60天的訓練營終于結束啦&#xff0c;感覺自己兩個月前做的這個決定非常正確&#xff0c;非常感謝卡哥和卡哥助手&#xff0c;從一個代碼沒有系統刷題沒有體系的小白到現在已經有了一些基礎&#xff0c;也具備一些刷題的習慣和手感&#xff0c;如果是我自己沒有規劃的刷可能…

【C++】二分查找:在排序數組中查找元素的第一個和最后一個位置

1.題目 難點&#xff1a;要求時間復雜度度為O(logn)。 2.算法思路 需要找到左邊界和右邊界就可以解決問題。 題目中的數組具有“二段性”&#xff0c;所以可以通過二分查找的思想進行解題。 代碼&#xff1a; class Solution { public:vector<int> searchRange(vect…