C++ | 面向對象 | 類

👻類

👾語法格式

class className{Access specifiers:				// 訪問權限DataType variable;			// 變量returnType functions() { }	// 方法
};

👾訪問權限

class className {public:// 公有成員protected:// 受保護成員private:// 私有成員
};

👽公有成員 public

公有成員在類外部可訪問,可不使用任何成員函數來設置和獲取公有變量的值

class Line {public:double length;void setLength(double len);double getLength(void);
};
double Line::getLength(void) { return length ; }
void Line::setLength(double len) { length = len; }...
Line line;
// 使用成員變量(正確,因為 length 公有) 
line.length = 10.0;
cout << line.length <<endl;
// 使用成員函數
line.setLength(6.0);
cout << line.getLength() <<endl;

👽私有成員 private

私有成員在類外部不可訪問,不可查看,只有友元函數可以訪問私有成員。沒有使用任何訪問修飾符默認私有。

class Box {public:double length;void setWidth(double wid);double getWidth(void);private:double width;
};
double Box::getWidth(void) { return width; }
void Box::setWidth( double wid ) { width = wid; }...
Box box;
// box.width = 10.0; 	// [Error] 'double Box::width' is private
box.setWidth(10.0);  	// 使用成員函數設置寬度
cout << box.getWidth() <<endl;

👽受保護成員 protected

受保護成員與私有成員相似,但有一點不同,受保護成員在**派生類(即子類)**中是可訪問的。

/* 基類 */ 
class Box {protected:double width;
};/* 派生類 */
class SmallBox: Box {  public:void setSmallWidth(double wid);double getSmallWidth();
};
double SmallBox::getSmallWidth() { return width; }
void SmallBox::setSmallWidth(double wid) { width = wid; }...
SmallBox box;
box.setSmallWidth(5.0);
cout << box.getSmallWidth() << endl;

👻類成員函數

👾語法格式

  • 定義在類定義內部

    class className{returnType functions(parameter list) { ... }
    };
    
  • 單獨使用范圍解析運算符 :: 定義

    class className{returnType functions(parameter list);
    };
    returnType class_name::functions(parameter list){ ... }
    

👾示例代碼

  • 定義在類定義內部

    class Box {public:double length;  // 長度double breadth; // 寬度double height;  // 高度double getVolume() { return length * breadth * height; }
    };
    
  • 單獨使用范圍解析運算符 :: 定義

    class Box {public:double length;  // 長度double breadth; // 寬度double height;  // 高度double getVolume();
    };double Box::getVolume() { return length * breadth * height; }
    

👻類構造函數

  • 類構造函數在每次創建類的新對象時執行。
  • 構造函數的名稱與類的名稱是完全相同的,不返回任何類型。
  • 構造函數可用于為某些成員變量設置初始值

👾無參構造函數

👽語法格式

class className{className() { ... }
};

👽示例代碼

class Line {public:Line() { cout << "Object is being created" << endl; }private:double length;
};...
Line line;	// 輸出:Object is being created

👾帶參構造函數

👽語法格式

class className{className(parameter list) { ... }
};

👽示例代碼

class Line {public:Line(double len) {length = len;cout << "Object is being created" << endl;}private:double length;
};...
Line line;	// 輸出:Object is being created

👾初始化列表構造函數

👽語法格式

類有多個字段 A、B、C 等需要進行初始化:

class className{className(int a,int b,int c): A(a), B(b), C(c) { ... }
};

👽示例代碼

class Line {public:Line(double len): length(len) { cout << "Object is being created" << endl; }private:double length;
};...
Line line;	// 輸出:Object is being created

等同語法:

Line(double len) {length = len;cout << "Object is being created" << endl;
}

注意:初始化類成員時,是按聲明的順序初始化,而不是按初始化列表的順序初始化,即:

class Base {public:// 按照 A -> B -> C 的順序初始化int A;int B;int C;// 而不是按照 C -> B -> A 的順序初始化Base(int a, int b, int c): C(c), B(b), A(a) {}
};

👻類析構函數

  • 類析構函數在每次刪除所創建的對象時執行。
  • 析構函數的名稱與類的名稱是完全相同的,在前面加 波浪號(~) 作為前綴,不返回任何值,不能帶有任何參數。
  • 析構函數有助于在跳出程序(比如關閉文件、釋放內存等)前釋放資源

👾語法格式

類有多個字段 A、B、C 等需要進行初始化:

class className{~className() { ... }
};

👾示例代碼

class Line {public:Line() { cout << "Object created" << endl; }  // 構造函數聲明~Line() { cout << "Object deleted" << endl; } // 析構函數聲明
};...
Line line;

一個類內可以有多個構造函數(相當于重載構造函數),只有一個析構函數

class Matrix {public:Matrix(int row, int col);       //普通構造函數Matrix(const Matrix& matrix);   //拷貝構造函數Matrix();                       //構造空矩陣的構造函數~Matrix();
};

👻類拷貝構造函數

👾語法結構

class className{// obj是對象引用,用于初始化另一個對象className (const className &obj) { }
};
  • 參數 obj —— 本類的引用

    • const 類型引用 —— 既能以常量對象(初始化后值不改變的對象)作為參數,也能以非常量對象作為參數初始化其他對象

    • const 類型引用 —— 一般不使用

👾被調用情況

  • 情況1:用一個對象初始化同類的另一個對象時,調用被初始化的對象的拷貝構造函數

    Base a2(a1);	
    Base a2 = a1;
    
    class Base {public:int num;// 一般構造函數Base(int n) {num = n;cout << "General Constructor called" << endl;}// 拷貝構造函數Base(const Base& a) {num = a.num;cout << "Copy Constructor called" << endl;}
    };...// 只調用a1的一般構造函數,輸出 General Constructor called
    Base a1(1);	
    // 只調用a2的拷貝構造函數,輸出 Copy Constructor called
    Base a2(a1);	
    Base a2 = a1;
    // 不調用
    a2 = a1;		
    

    注意,Base a2 = a1; 是初始化語句,不是賦值語句。

    賦值語句的等號左邊是一個早已有定義的變量,不會引發復制構造函數的調用,

    Base a1(1);	// 調用a1的一般構造函數
    Base a2(a1);	// 調用a2的拷貝構造函數
    a2 = a1;		// 不調用,因為 a2 早已生成且初始化,不會引發拷貝構造函數
    

    只會調用被初始化的對象的拷貝構造函數,不會調用其一般構造函數

  • 情況2:函數參數是類的對象,當函數調用時,調用對象的拷貝構造函數

    class Base {public:// 一般構造函數Base() { cout << "General Constructor called" << endl; };// 拷貝構造函數Base(Base& a) { cout << "Copy constructor called" << endl; }
    };
    void Function(Base a) {}...Base a;		// 調用a的一般構造函數,輸出 General Constructor called
    Function(a);	// 調用a的拷貝構造函數,輸出 Copy constructor called
    
    • 對象作為形參,函數被調用時,生成形參要用拷貝構造函數,會帶來時間開銷
    • 對象的引用作為形參,無時間開銷,但有一定的風險,因為如果形參的值發生改變,實參值也會改變

    如果要確保實參值不改變,又希望避免拷貝構造函數的開銷,解決辦法是將形參聲明為對象的 const 引用:

    void Function(const Base &a){...
    }
    
  • 情況3:函數返回值是類的對象,當函數返回時,調用對象的拷貝構造函數

    class Base {public:int num;// 一般構造函數Base(int n) {num = n;cout << "General Constructor called" << endl;}// 拷貝構造函數Base(const Base& a) {num = a.num;cout << "Copy constructor called" << endl;}
    };Base Func() {Base a(4);	// 調用一般構造函數,輸出 General Constructor calledreturn a;
    }...int a = Func().num;	// 調用拷貝構造函數,輸出 Copy constructor called
    

    有些編譯器出于程序執行效率的考慮,編譯時進行優化,函數返回值對象不用拷貝構造函數,不符合C++標準

👾深拷貝和淺拷貝

👽淺拷貝

  • 使用情況:基本類型數據、簡單對象
  • 原理:按位復制內存
// 基本類型數據
int a = 10;
int b = a;
// 簡單對象
class Base {public:Base(): m_a(0), m_b(0) { }Base(int a, int b): m_a(a), m_b(b) { }private:int m_a;int m_b;
};Base obj1(10, 20);
Base obj2 = obj1;

👽深拷貝

  • 使用情況
    • 持有其它資源的類(如動態分配的內存、指向其他數據的指針)
    • 標準模板庫(STL)中 string、vector、stack 等
    • 創建對象時進行一些預處理工作,比如統計創建過的對象的數目、記錄對象創建的時間等
  • 原理:顯式定義拷貝構造函數
  • 過程
    • 會將原有對象的所有成員變量拷貝給新對象
    • 會為新對象再分配一塊內存,并將原有對象所持有的內存也拷貝過來
  • 結果:原有對象和新對象所持有的動態內存相互獨立,更改一個對象的數據不影響另一個對象
// 持有其它資源的類(如動態分配的內存、指向其他數據的指針)
#include <cstdlib>
#include <iostream>
using namespace std;class Array {public:Array(const int len) {m_len = len;m_p = (int*)calloc(m_len, sizeof(int));}Array(const Array& arr) {this->m_len = arr.m_len;this->m_p = (int*)calloc(this->m_len, sizeof(int));memcpy(this->m_p, arr.m_p, m_len * sizeof(int));}~Array() { free(m_p); }int operator[](int i) const { return m_p[i]; }int& operator[](int i) { return m_p[i]; }int length() const { return m_len; }private:int m_len;int* m_p;
};void printArray(const Array& arr) {int len = arr.length();for(int i = 0; i < len; i++) { if(i == len - 1) { cout << arr[i] << endl; } else { cout << arr[i] << ", "; } }
}...int main() {Array arr1(10);for(int i = 0; i < 10; i++)arr1[i] = i;Array arr2 = arr1;arr2[5] = 100;arr2[3] = 29;printArray(arr1); // 輸出:0, 1, 2, 3, 4, 5, 6, 7, 8, 9printArray(arr2); // 輸出:0, 1, 2, 29, 4, 100, 6, 7, 8, 9
}
// 創建對象時進行一些預處理工作
#include <iostream>
#include <ctime>
#include <windows.h>
using namespace std;class Base {public:Base(int a = 0, int b = 0) {m_a = a;m_b = b;m_count++;m_time = time(nullptr);}Base(const Base& obj) {this->m_a = obj.m_a;this->m_b = obj.m_b;this->m_count++;this->m_time = time(nullptr);}static int getCount() { return m_count; }time_t getTime() const { return m_time; }private:int m_a;int m_b;time_t m_time;      //對象創建時間static int m_count; //創建過的對象的數目
};int Base::m_count = 0;...int main() {Base obj1(10, 20);cout << "obj1: count = " << obj1.getCount() << ", time = " << obj1.getTime() << endl;// 輸出:obj1: count = 1, time = 1740055359Sleep(3000);Base obj2 = obj1;cout << "obj2: count = " << obj2.getCount() << ", time = " << obj2.getTime() << endl;// 輸出:obj2: count = 2, time = 1740055362return 0;
}

👻類靜態成員

👾類靜態成員變量

👽聲明

使用 關鍵字 static 把類成員聲明為靜態

class Box {public:static int objectCount; // 聲明靜態變量Box() { objectCount++; } // 每次創建對象時調用構造函數,靜態變量值加 1
};

無論創建多少個類的對象,靜態成員只有一個副本,在類的所有對象中是共享的。

👽定義

在類外部通過 范圍解析運算符 :: 定義靜態變量

class Box {public:static int objectCount; // 聲明靜態變量Box() { objectCount++; } 
};
// 僅定義卻不初始化 類靜態成員
int Box::objectCount;

無論是否初始化,必須定義,否則報錯:

(.rdata$.refptr._ZN3Box11objectCountE[.refptr._ZN3Box11objectCountE]+0x0): undefined reference to `Box::objectCount'

👽初始化

// 定義+初始化 類靜態成員
int Box::objectCount = 0;

若不初始化,則在創建第一個對象時所有靜態數據初始化為零

👽訪問

  • 使用 范圍解析運算符 :: 訪問類靜態變量
Box box1();    // 聲明 box1
Box box2();    // 聲明 box2
cout << "創建對象總數: " << Box::objectCount << endl;

👾類靜態成員函數

👽聲明定義

  • 使用 關鍵字 static 把類成員聲明為靜態
class Box {public:static int objectCount; // 聲明靜態變量Box() { objectCount++; }static int getCount() { // 聲明定義靜態函數return objectCount;}
};
  1. 普通成員函數有 this 指針,可以訪問類中的任意成員
  2. 靜態成員函數沒有 this 指針,只能訪問靜態成員變量其他靜態成員函數類外部的其他函數

👽使用

  • 使用 范圍解析運算符 :: 訪問類靜態變量
cout << "創建對象總數: " << Box::getCount() << endl; // 對象不存在時 也能被調用
Box box1();    // 聲明 box1
Box box2();    // 聲明 box2
cout << "創建對象總數: " << Box::getCount() << endl;

靜態成員函數即使 類對象不存在 也能被調用


👻友元

👾友元函數

  • 類的友元函數定義在類外部,但有權訪問類的私有成員、保護成員
  • 盡管友元函數的原型在類的定義中出現,但友元函數不是成員函數

👽聲明

使用 關鍵字 friend 把函數聲明為友元函數

class Box {double width;public:Box(double w): width(w) {}friend void printWidth(Box box);  // 在函數前使用關鍵字 friend
};

👽定義

class Box {double width;public:Box(double w): width(w) {}friend void printWidth(Box box);
};/* printWidth() 不是任何類的成員函數,但因為它是 Box 的友元,可直接訪問該類的任何成員 */
void printWidth(Box box) { cout << "Width of box : " << box.width <<endl;}

👽使用

Box box;
box.setWidth(10.0);
printWidth(box); 	// 使用友元函數訪問Box中的私有成員

👾友元類

👽聲明定義

class Box {public:Box(double w): width(w) {}friend class BigBox;private:double width;
};/* BigBox是Box的友元類,它可以直接訪問Box類的任何成員 */
class BigBox {public :void printWidth(Box& box) { cout << "Width of box : " << box.width << endl; }
};

👽使用

Box box(10.0);
BigBox big;
big.printWidth(box); // 使用友元類中的方法訪問Box中的私有成員

👻 this 指針

  • this 指針是一個特殊的指針,它指向當前對象的實例,每一個對象都能通過 this 指針來訪問自己的地址。
  • 當一個對象的成員函數被調用時,編譯器會隱式地傳遞該對象的地址作為 this 指針。
  • 友元函數沒有 this 指針,因為友元不是類的成員
class MyClass {private:int value;public:// 可以明確地告訴編譯器想訪問當前對象的成員變量,而不是函數參數或局部變量,避免命名沖突void setValue(int value) { this->value = value; } void getValue() { return this->value; }
};...MyClass obj;
obj.setValue(42);
int value = obj.getValue();

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

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

相關文章

從零開始用react + tailwindcss + express + mongodb實現一個聊天程序(五) 實現登錄功能

1.登錄頁面 完善登錄頁面 和注冊差不多 直接copy signUpPage 內容 再稍微修改下 import { useState } from "react"; import { useAuthStore } from "../store/useAuthStore"; import { MessageSquare,Mail,Lock,Eye, EyeOff,Loader2} from "lucide…

Spring Boot電影評論網站系統設計與實現

隨著互聯網和娛樂產業的發展&#xff0c;電影評論網站逐漸成為人們分享觀影體驗、交流影評的重要平臺。本文將介紹一個基于Spring Boot框架開發的電影評論網站系統的功能設計與實現方案。 功能模塊概述 該電影評論網站系統分為管理員模塊和用戶模塊兩大核心部分&#xff0c;以…

XFeat:輕量級的深度學習圖像特征匹配

一、引言&#xff1a;圖像特征匹配的挑戰與XFeat的突破 在計算機視覺領域&#xff0c;圖像特征匹配是視覺定位&#xff08;Visual Localization&#xff09;、三維重建&#xff08;3D Reconstruction&#xff09;、增強現實&#xff08;AR&#xff09;等任務的核心基礎。傳統方…

【TVM教程】為 NVIDIA GPU 自動調度神經網絡

Apache TVM 是一個深度的深度學習編譯框架&#xff0c;適用于 CPU、GPU 和各種機器學習加速芯片。更多 TVM 中文文檔可訪問 →https://tvm.hyper.ai/ 作者&#xff1a;Lianmin Zheng 針對特定設備和工作負載的自動調優對于獲得最佳性能至關重要。本文介紹如何使用 auto-sched…

postgresql postgis擴展相關

項目 下載地址 http://rpmfind.net/linux/rpm2html/search.php?queryprotobuf(x86-64) Postgis Index of /postgis/source/ proj4 Index of /proj/ geos Index of /geos/ libxml2 ftp://xmlsoft.org/libxml2/ Index of /sources Json-c Releases json-c/json-c G…

解鎖健康密碼,擁抱養生生活

在快節奏的現代生活中&#xff0c;健康養生愈發重要&#xff0c;它是我們保持活力、預防疾病、享受美好生活的關鍵。那究竟如何開啟健康養生之旅呢&#xff1f; 合理飲食是養生基石。遵循 “食物多樣&#xff0c;谷類為主” 原則&#xff0c;每日攝入谷薯類、蔬菜水果、畜禽魚蛋…

JavaWeb中的cookie使用

Cookie 1、Cookie是服務端向客戶端響應的一小段數據&#xff0c;最終存放在客戶端中&#xff1b;之后客戶端每次向服務端發送請求&#xff0c;都會在請求頭中攜帶cookie 2、cookie是有時效性的&#xff0c;默認是Session級別&#xff08;整個瀏覽器關閉才會消失&#xff0c;內存…

el-input實現金額輸入

需求&#xff1a;想要實現一個輸入金額的el-input&#xff0c;限制只能輸入數字和一個小數點。失焦數字轉千分位&#xff0c;聚焦轉為數字&#xff0c;超過最大值&#xff0c;紅字提示 效果圖 失焦 聚焦 報錯效果 // 組件limitDialog <template><el-dialog:visible.s…

AcWing 藍橋杯集訓·每日一題2025·密接牛追蹤2

密接牛追蹤2 農夫約翰有 N 頭奶牛排成一排&#xff0c;從左到右依次編號為 1~N。 不幸的是&#xff0c;有一種傳染病正在蔓延。 最開始時&#xff0c;只有一部分奶牛受到感染。 每經過一個晚上&#xff0c;受感染的牛就會將病毒傳染給它左右兩側的牛&#xff08;如果有的話…

30 分鐘從零開始入門 CSS

HTML CSS JS 30分鐘從零開始入門拿下 HTML_html教程-CSDN博客 30 分鐘從零開始入門 CSS-CSDN博客 JavaScript 指南&#xff1a;從入門到實戰開發-CSDN博客 前言 最近也是在復習&#xff0c;把之前沒寫的博客補起來&#xff0c;之前給大家介紹了 html&#xff0c;現在是 CSS 咯…

LabVIEW圖像識別抗干擾分析

問題描述 在基于LabVIEW的探針定位系統中&#xff0c;存在兩個核心技術難點&#xff1a; 相機畸變導致初始定位誤差&#xff1a;非線性畸變使探針無法通過坐標變換直接精確定位&#xff0c;需采用粗定位圖像修正的兩段式控制策略。 圖像識別可靠性不足&#xff1a;復雜背景&a…

淺顯易懂HashMap的數據結構

HashMap 就像一個大倉庫&#xff0c;里面有很多小柜子&#xff08;數組&#xff09;&#xff0c;每個小柜子可以掛一串鏈條&#xff08;鏈表&#xff09;&#xff0c;鏈條太長的時候會變成更高級的架子&#xff08;紅黑樹&#xff09;。下面用超簡單的例子解釋&#xff1a; ?壹…

drupal如何支持多語言

Drupal 支持多語言的功能強大&#xff0c;可以幫助網站實現多語言內容管理。以下是如何在 Drupal 中配置和啟用多語言支持的步驟&#xff1a; 1. 啟用多語言模塊 首先&#xff0c;您需要確保已啟用 Drupal 的相關模塊。這些模塊包括&#xff1a; Language&#xff08;語言&a…

【HarmonyOS Next】鴻蒙應用折疊屏設備適配方案

【HarmonyOS Next】鴻蒙應用折疊屏設備適配方案 一、前言 目前應用上架華為AGC平臺&#xff0c;都會被要求適配折疊屏設備。目前華為系列的折疊屏手機&#xff0c;有華為 Mate系列&#xff08;左右折疊&#xff0c;華為 Mate XT三折疊&#xff09;&#xff0c;華為Pocket 系列…

SE注意力機制詳解:從原理到應用,全面解析Squeeze-and-Excitation模塊

Squeeze-and-Excitation (SE) 模塊的原理與應用 1. 引言&#xff1a;注意力機制的意義 在深度學習領域&#xff0c;注意力機制&#xff08;Attention Mechanism&#xff09;通過模擬人類視覺的“聚焦”特性&#xff0c;賦予模型動態調整特征重要性的能力。傳統卷積神經網絡&a…

Python基礎大全:Python變量詳解

以下是 Python 變量的詳細解析&#xff1a; 1. 變量的本質 Python 變量本質上是一個 指向對象的引用&#xff08;類似標簽&#xff09;&#xff0c;而不是存儲數據的容器。 變量賦值 a 10 時&#xff0c;Python 會創建一個整數對象 10&#xff0c;然后讓變量 a 指向這個對象…

減少內存占用的兩種方法|torch.no_grad和disable_torch_init

方法區別 在 PyTorch 中&#xff0c;disable_torch_init 和 torch.no_grad() 是兩種完全不同的機制&#xff0c;它們的作用和目的不同&#xff0c;以下是它們的區別&#xff1a; 1. disable_torch_init 作用&#xff1a;disable_torch_init 通常用于某些特定的框架或庫中&am…

數據挖掘工程師的技術圖譜和學習路徑

數據挖掘工程師的技術圖譜和學習路徑: 1.基礎知識 數據挖掘工程師是負責從大量數據中發現潛在模式、趨勢和規律的專業人士。以下是數據挖掘工程師需要掌握的基礎知識: 數據庫知識:熟悉關系數據庫和非關系數據庫的基本概念和操作,掌握SQL語言。 統計學基礎:了解統計學的基…

UE5 Computer Shader學習筆記

首先這里是綁定.usf文件的路徑&#xff0c;并聲明是用聲明著色器 上面就是對應的usf文件路徑&#xff0c;在第一張圖進行鏈接 Shader Frequency 的作用 Shader Frequency 是 Unreal Engine 中用于描述著色器類型和其執行階段的分類。常見的 Shader Frequency 包括&#xff1a…

提示學習(Prompting)

提示學習&#xff08;Prompting&#xff09;是一種利用預訓練語言模型&#xff08;Pre-trained Language Models, PLMs&#xff09;來完成特定任務的方法。它的核心思想是通過設計特定的提示&#xff08;Prompt&#xff09;&#xff0c;將任務轉化為預訓練模型能夠理解的形式&a…