對象與對象數組

對象與對象數組

實驗介紹

本章節主要介紹對象數組和對象成員。在實際的開發中,對象數組和對象成員是經常使用的,所以首先需要學習對象數組與對象成員的各種使用方法。

提示:為了方便課程講解,示例代碼使用類內定義的方式實現,如果自己動手做實驗的時候希望能夠使用分文件類外定義的方式來編寫代碼。

知識點
  • 對象數組
    • 實例化對象數組
    • 堆上操作對象數組
  • 對象成員
    • 構造和析構順序
    • 初始化對象成員

對象數組

假設定義了一個學生類,現在要實例化一個班的學生,如果逐個對學生進行實例化操作那肯定是非常麻煩的,這時使用對象數組就能很方便的完成編寫。假設有一個點類,如果實例化一個矩形也可以使用對象數組的方式。

點類 - 示例代碼 1

定義一個點類,在本小節以后的示例代碼中都是用該類,在以下的示例代碼中盡量使用之前學到過的知識點。

為了方便查看運行結果,分別在構造函數、拷貝構造函數和析構函數中打印函數的名稱。

#include <iostream>
using namespace std;class Point
{
public:// 使用帶參數默認構造函數,并使用初始化列表初始化 x,yPoint(double x = 0, double y = 0) : x(x), y(y) {//cout << "Point(double x = 0, double y = 0)" << endl;cout << "Point(double x = " << x << ", double y = " << y << ")" << endl;}// 拷貝構造函數Point(const Point & p) {//cout << "Point(const Point &p)" << endl;// 打印點的值cout << "Point(const Point &p:(" << p.x << ", " << p.y << ")" << endl;this->x = p.x;this->y = p.y;}// 析構函數,由于沒有申請內存,析構函數中不需要做什么~Point() {//cout << "~Point()" << endl;cout << "~Point():(" << x << ", " << y << ")" << endl;}// x, y 綁定的成成員函數void setPoint(const Point &p) {this->x = p.x;this->y = p.y;}void setPoint(double x, double y) {this->x = x;this->y = y;}void setX(double x) { this->x = x; }void setY(double y) { this->y = y; }double getX() { return x; }double getY() { return y; }
private:double x;double y;
};

棧上實例化

示例代碼 2

為了效果演示,示例代碼將對象數組定義在一個函數中,可以在函數執行完之后調用對象數組的析構函數。

// 棧上實例化
void stackInstantiation()
{// 實例化對象數組Point point[3];// 對象數組操作cout << "p[0]: (" << point[0].getX() << ", " << point[0].getY() << ")" << endl;cout << "p[1]: (" << point[1].getX() << ", " << point[1].getY() << ")" << endl;cout << "p[2]: (" << point[2].getX() << ", " << point[2].getY() << ")" << endl;point[0].setPoint(3, 4);cout << "p[0]: (" << point[0].getX() << ", " << point[0].getY() << ")" << endl;
}int main()
{stackInstantiation();return 0;
}

運行結果:

棧上實例化對象數組小結:

  • 實例化對象數組時,每一個對象的構造函數都會被執行。
  • 系統自動銷毀棧上對象數組,并且銷毀對象數組時,每一個對象析構函數都會被執行。
  • 訪問對象數組時使用 [ i ] 的方式訪問相應位置的對象。
  • 建議將類數據成員都初始化,可以使用默認值初始化。
  • void setPoint(const Point &p); // 如果是自定義類作為參數時,建議使用引用的方式傳入參數,如果該參數在函數中無需修改且沒有輸出,建議加上 const
示例代碼 3
void stackInstantiation()
{Point point[3];Point *p = point;cout << "p: (" << p->getX() << ", " << p->getY() << ")" << endl;p++;cout << "p: (" << p->getX() << ", " << p->getY() << ")" << endl;p++;cout << "p: (" << p->getX() << ", " << p->getY() << ")" << endl;point[2].setPoint(3, 4);cout << "p: (" << p->getX() << ", " << p->getY() << ")" << endl;
}int main()
{stackInstantiation();return 0;
}

運行結果:試驗中聲明的是對象數組,但是數組其本身也是可以當做指針使用。

堆上實例化

在堆上操作對象數據會比在棧上操作對象數組復雜,但卻比棧上操作更加的靈活,如果數據量比較大建議在堆上操作。

示例代碼 4
int main()
{// 堆上實例化對象數組Point *point = new Point[3];cout << "p[0]: (" << point[0].getX() << ", " << point[0].getY() << ")" << endl;cout << "p[1]: (" << point[1].getX() << ", " << point[1].getY() << ")" << endl;cout << "p[2]: (" << point[2].getX() << ", " << point[2].getY() << ")" << endl;point[0].setPoint(3, 4);cout << "p[0]: (" << point[0].getX() << ", " << point[0].getY() << ")" << endl;// 釋放內存delete [] point;point = nullptr;return 0;
}

運行結果:按照示例代碼 3 中的訪問方式與棧上訪問方式是一樣的,跟棧上訪問的結果也是一樣的。但是別急,后面還有堆上特有的操作。

示例代碼 5

在堆上操作對象數據會比在棧上操作對象數組復雜,但卻比棧上操作更加的靈活,如果數據量會比較大建議在堆上操作。

// 堆上實例化
int main()
{// 實例化對象Point *p = new Point[3];Point *point = p;cout << "point: (" << point->getX() << ", " << point->getY() << ")" << endl;p++;cout << "point: (" << point->getX() << ", " << point->getY() << ")" << endl;p++;cout << "point: (" << point->getX() << ", " << point->getY() << ")" << endl;point->setPoint(3, 4);cout << "point: (" << point->getX() << ", " << point->getY() << ")" << endl;cout << "p: (" << p->getX() << ", " << p->getY() << ")" << endl;// 釋放內存delete [] point;point = nullptr;return 0;
}

運行結果:發現使用指針的方式一樣可以訪問對象數組,但是使用時也要注意幾個問題。

  • 使用 -> 的方式來訪問類成員函數,并且不需要使用下標。
  • Point *point = p; 可以發現我又重新聲明一個指針,因為一個指針只能指向一個對象,通過指針 ++ 或者 -- 運算符的方式來訪問對象數組中對象。

示例代碼 6

強調堆上申請空間與釋放空間的問題,請注意一下代碼與之前的異同之處,在銷毀對象數組時使用的是 delete point; 而在之前的示例代碼中使用的是 delete [] point; 來銷毀對象數組的。

// 堆上實例化
int main()
{// 實例化對象Point *point = new Point[3];cout << "point: (" << point->getX() << ", " << point->getY() << ")" << endl;point++;cout << "point: (" << point->getX() << ", " << point->getY() << ")" << endl;point++;cout << "point: (" << point->getX() << ", " << point->getY() << ")" << endl;point->setPoint(3, 4);cout << "point: (" << point->getX() << ", " << point->getY() << ")" << endl;// 指針使用完成后需要將指針指到起始地址point -= 2;// 釋放內存delete point;point = nullptr;return 0;
}

運行結果:

  • linux 環境直接運行報錯,但在 Windows 環境下可以正確運行,這就造成了內存泄漏。

對象成員

對象成員即對象中包含其他的對象。

這里示例代碼將繼續使用示例代碼 1 中的點類。

示例代碼 7

首先看一下當對象 A 有對象 B 時調用構造函數與析構函數的順序。

class Line
{
public:Line(const Point & pA, const Point &pB) : pointA(pA), pointB(pB) {cout << "Line(const Point & pA, const Point &pB)" << endl;}Line(double aX, double aY, double bX, double bY) : pointA(aX, aY), pointB(bX, bY) {cout << "Line(double aX, double aY, double bX, double bY)" << endl;}~Line() {cout << "~Line()" << endl;}
private:Point pointA;Point pointB;
};int main()
{// 實例化Line *line = new Line(1, 2, 3, 5);// 釋放內存delete line;line = nullptr;return 0;
}

運行結果:可以看到先調用 pointA 的構造函數,再調用 pointB 的構造函數,最后調用 Line 的構造函數;而析構函數時正好反過來的。這也是為什么當對象成員沒有默認構造函數時必須要使用初始化列表的原因,因為對象成員先于對象初始化。

示例代碼 8

如果將對象成員類型作為參數輸入時看看其調用構造函數以及析構函數的順序。

int main()
{// 實例化Line *line = new Line(Point(1, 2), Point(3, 5));// 釋放內存delete line;line = nullptr;return 0;
}

運行結果:對象成員類型作為參數傳入時,傳入的參數時會臨時創建兩個對象,初始化完成后臨時對象自動銷毀。

示例代碼 9
int main()
{Line *p = new Line(1, 2, 3, 4);cout << "sizeof (p) = " << sizeof (p) << endl;cout << "sizeof (Line) = " << sizeof (Line) << endl;delete p;p = nullptr;return 0;
}

運行結果:p 指針占 8 字節,Line 類中有兩個 Point 類數據成員,Point 類有兩個 double 類型數據成員,所以 Line 一共占 32 個字節。

實驗總結
  • 使用對象數組時會調用每個對象的構造函數和析構函數。
  • newdeletenew []delete [] 一定要配套使用。
  • 不要越界,不管是棧還是堆,訪問數組時都不要越界。
  • 對象數組指針變量本身就是一個指針。
  • 堆上實例化的數組,要注意指針使用方法。
  • 如果是做項目,要考慮使用在堆上實例化申請內存,棧空間比堆空間小很多。
  • 當對象 A 中有常量時必須使用初始化列表。
  • 當對象 A 有其他的對象 B 并且對象 B 沒有默認構造參數時需要使用初始化列表。
  • 除了以上兩種情況,可以不使用初始化列表,但是推薦使用初始化列表。
  • 對象數據成員和對象成員先于對象初始化。
  • 在實例化對象時需要清楚初始化數據成員的順序。

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

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

相關文章

19 redis緩存數據同步問題

1、緩存穿透 指緩存和數據庫中都沒有的數據&#xff0c;而用戶不斷發起請求。由于緩存不命中&#xff0c;并且出于容錯考慮&#xff0c;如果從存儲層查不到數據則不寫入緩存&#xff0c;這將導致這個不存在的數據每次請求都要到存儲層去查詢&#xff0c;緩存就沒有意義了。 在…

掌控安全 -- header注入

http header注入 該注入是指利用后端驗證客戶端口信息&#xff08;比如常用的cookie驗證&#xff09;或者通過http header中獲取客戶端的一些信息&#xff08;比如useragent用戶代理等其他http header字段信息&#xff09;&#xff0c;因為這些信息是會重新返回拼接到后臺中的&…

JAVA定時任務技術總結

在日常的項目開發中&#xff0c;多多少少都會涉及到一些定時任務的需求。例如每分鐘掃描超時支付的訂單&#xff0c;每小時清理一次數據庫歷史數據&#xff0c;每天統計前一天的數據并生成報表&#xff0c;定時去掃描某個表的異常信息&#xff08;最終一致性的方案也可能涉及&a…

java面試題-描述下Object中常用的方法

遠離八股文&#xff0c;面試大白話&#xff0c;通俗且易懂 看完后試著用自己的話復述出來。有問題請指出&#xff0c;有需要幫助理解的或者遇到的真實面試題不知道怎么總結的也請評論中寫出來&#xff0c;大家一起解決。 java面試題匯總-目錄-持續更新中 這個沒辦法&#xff0c…

31、卷積 - 參數 dilation 以及空洞卷積

在卷積算法中,還有一個不常見的參數叫做dilation(中文:膨脹)。 很多同學可能沒聽說過這個參數,下面看看這個參數有什么作用,用來控制什么的。 我們還是放這個經典的卷積運算圖,圖中是看不出 dilation 這個參數的存在的。 如果再換一張圖呢,發現兩圖的區別了嗎? 沒錯…

怎么去評估數據資產?一個典型的政務數據資產評估案例

據中國資產評估協會《數據資產評估指導意見》&#xff0c;數據資產評估主要是三個方法&#xff1a;市場法、成本法和收益法。之前小億和大家分享了數據資產評估方法以及價值發揮的路徑&#xff0c;今天結合一個案例來具體講解一下怎么去評估數據資產。 這個案例是一個典型的一個…

tmux常見會話管理命令

tmux常見會話管理命令 新建會話 tmux new -s <session-name> 查看會話 會話內外都可以用tmux ls或者tmux list-session 分離會話 如果命令行可以輸入命令&#xff0c;則可以選擇輸入命令tmux detach 如果命令行沒法輸入命令&#xff0c;可以按下commandb以后按d …

SAM+使用SAM應用數據集完成分割

什么是SAM&#xff1f; SAM(Segment Anything Model&#xff09;是由 Meta 的研究人員團隊創建和訓練的深度學習模型。在 Segment everything 研究論文中&#xff0c;SAM 被稱為“基礎模型”。 基礎模型是在大量數據上訓練的機器學習模型&#xff08;通常通過自監督或半監督學習…

CV計算機視覺每日開源代碼Paper with code速覽-2023.12.6

點擊計算機視覺&#xff0c;關注更多CV干貨 論文已打包&#xff0c;點擊進入—>下載界面 點擊加入—>CV計算機視覺交流群 1.【基礎網絡架構&#xff1a;Transformer】Rejuvenating image-GPT as Strong Visual Representation Learners 論文地址&#xff1a;https://a…

云原生Kubernetes系列 | Docker/Kubernetes的卷管理

云原生Kubernetes系列 | Docker/Kubernetes的卷管理 1. Docker卷管理2. Kubernetes卷管理2.1. 本地存儲2.1.1. emptyDir2.1.2. hostPath2.2. 網絡存儲2.2.1. 使用NFS2.2.2. 使用ISCSI2.3. 持久化存儲2.3.1. PV和PVC2.3.2. 訪問模式2.3.3. 回收策略1. Docker卷管理

從零開始搭建企業管理系統(六):RBAC 權限管理設計

RBAC 權限管理設計 前言權限分類功能權限設計什么是 RBACRBAC 組成RBAC 模型分類基本模型RBAC0角色分層模型RBAC1角色限制模型RBAC2統一模型RBAC3 RBAC0 權限設計用戶管理角色管理權限管理關聯表 總結 前言 作為一個后臺管理系統&#xff0c;權限管理是一個繞不開的話題&#…

視頻剪輯:視頻創意制作,背景圖片融合視頻制作畫中畫效果

隨著社交媒體的興起&#xff0c;視頻制作不再僅僅是專業人士的專利。每個人都可以通過一些技巧&#xff0c;創作出獨特而富有吸引力的視頻內容。視頻剪輯是一種非常重要的技術&#xff0c;它能讓視頻從平淡無奇變為生動有趣。背景圖片融合視頻制作畫中畫效果&#xff0c;也能增…

vm的centos本地配置yum

vm的centos本地配置yum 關于上篇文章vmware安裝centos7總結 出現關于配置yum源wget找不到命令&#xff0c;但是沒安裝yum就沒法下載wget&#xff0c;也就沒法使用wget 所以我們本地配置yum源&#xff0c;不用wget那個命令了 &#x1f4d5;步驟&#xff1a; cd /etc/yum.repo…

springboot利用easyexcel在瀏覽器中下載excel

前言 項目中操作excel是一種很常用的功能&#xff0c;比如下載一份excel的報價單。這篇文章會介紹一款excel的處理工具以及導出遇到的三個常見異常(重要)。 之前遇到一個這樣的需求&#xff1a;后臺管理頁面&#xff0c;點擊下載按鈕&#xff0c;下載一份excel格式的報價清單…

《人工智能導論》知識思維導圖梳理【1~5章節】

文章目錄 說明第一章 緒論人工只能概述 第二章 知識表示和知識圖譜一階謂詞邏輯和知識表示法產生式表示和框架表示法 第三章 確定性推理方法推理的基本概念自然演繹推理歸結演繹推理謂詞公式化子句集魯賓孫歸結原理歸結反演歸結反演求解問題 第四章 不確定性推理方法似然推理可…

npm run build時提示vue/types/jsx.d.ts中的錯誤

解決方法一&#xff1a; 可能是因為vue版本過高引起的 我直接將package.json中vue以及vue-template-compiler的版本的前面^去掉&#xff0c;安裝指定的版本 注意&#xff1a;vue和vue-template-compiler需要版本一致 參考鏈接&#xff1a;鏈接 解決方法二&#xff1a; 如果如…

線上問題得解決

問題&#xff1a; 最近碰到一個比較棘手但是比較低級的問題&#xff0c;一直沒有找到原因&#xff0c;苦找了兩天才發現問題。場景就是訂單做了某一個操作之后&#xff08;比如揀貨完成&#xff09;然后到下一步&#xff08;下道口&#xff09;。 但是線上幾萬筆訂單 &#xf…

QT使用SQLite 超詳細(增刪改查、包括對大量數據快速存儲和更新)

QTSQLite 在QT中使用sqlite數據庫&#xff0c;有多種使用方法&#xff0c;在這里我只提供幾種簡單&#xff0c;代碼簡短的方法&#xff0c;包括一些特殊字符處理。在這里也給大家說明一下&#xff0c;如果你每次要存儲的數據量很大&#xff0c;建議使用事務&#xff08;代碼中…

canvas 有趣的彈簧效果

先上效果 兩個小球之間有一根彈簧&#xff0c;這里有一條線表示&#xff0c;其中左球固定&#xff0c;在點擊開始后&#xff0c;右球開始做自由落體 思路 先做受力分析 經過受力分析可以發現&#xff0c;整個系統一共有三個力在起作用&#xff0c;我們分別把他們求出來并合成…

控制臺打印如來佛圖像

代碼 System.out.println(" _ooOoo_ \n"" o8888888o \n"" 88 \".\" 88 …