C++ 入門四:類與對象 —— 面向對象編程的核心基石

一、類的定義

1. 類的基本形式

class 類名 {
public:       // 公有成員(類內外均可訪問)數據類型 數據成員;       // 公有數據成員數據類型 成員函數(參數列表);  // 公有成員函數聲明
protected:    // 保護成員(類內和派生類可訪問)數據類型 保護數據成員;數據類型 保護成員函數(參數列表);
private:     // 私有成員(僅類內可訪問)數據類型 私有數據成員;數據類型 成員函數(參數列表);  // 私有成員函數聲明
};  // 類定義結束必須加分號

2. 詳細說明

  • 成員分類:類包含兩種成員:
    • 數據成員:描述類的屬性,如學生類中的姓名年齡
    • 成員函數:描述類的行為,如學生類中的設置年齡獲取成績
  • 訪問權限
    • public(公有):成員可在類外直接訪問,例如對象名.公有成員
    • protected(保護):成員可在類內和派生類中訪問,類外不可直接訪問。
    • private(私有):僅類內成員函數或友元可訪問,類外和派生類(除非友元)不可直接訪問。
  • 成員函數定義
    • 類內定義:直接在類體中編寫函數體,自動成為內聯函數(隱式inline)。
    • 類外定義:使用類名::作用域限定符,例如:
      void 類名::成員函數(參數列表) { /* 函數體 */ }
      

3. 示例:定義學生類

class Student {
public:// 公有數據成員char name[20];  // 姓名int age;        // 年齡// 公有成員函數(類內定義)void set_score(float s) {  // 設置成績(私有成員)score = s;}// 公有成員函數(類外定義)float get_score();  // 獲取成績聲明protected:int grade;  // 年級(保護成員,派生類可訪問)private:float score;  // 成績(私有成員,僅類內訪問)
};// 類外定義成員函數
float Student::get_score() {return score;  // 訪問私有成員score
}

二、對象的定義與成員訪問

1. 對象定義

  • 語法類名 對象名;?或?類名 對象名(參數列表);(調用帶參構造函數)
  • 示例
    Student stu1;         // 定義對象stu1(調用默認構造函數)
    Student stu2("張三", 18);  // 假設存在帶參構造函數
    

2. 成員訪問

  • 公有成員:直接通過對象名.成員名訪問。
    stu1.age = 18;       // 合法,age是公有成員
    strcpy(stu1.name, "李四"); // 合法
    
  • 私有 / 保護成員:通過公有成員函數間接訪問。
    stu1.set_score(90.5); // 合法,調用公有函數設置私有成員score
    // stu1.score = 90.5;  // 非法,score是私有成員
    

三、構造函數:對象的初始化

在面向對象編程中,對象的初始化是一個關鍵環節。構造函數作為類的特殊成員函數,承擔著初始化對象的重要職責。下面將從基礎概念到高級用法逐步解析構造函數的核心知識。

1. 構造函數概述

語法規則
  • 函數名:必須與類名完全相同(包括大小寫)。
  • 返回值:沒有返回值(不能寫void)。
  • 調用時機:創建對象時自動調用(棧上定義、堆上new操作、函數返回對象等場景)。
核心作用
  • 成員初始化:為對象的成員變量賦初始值(如數值類型設為默認值、指針指向有效內存)。
  • 資源分配:為對象分配運行所需資源(如動態內存、文件句柄、網絡連接等)。
示例:基礎構造函數
class Book {
public:// 構造函數:初始化書名和頁數Book() {strcpy(title, "未命名");  // 初始化C風格字符串pages = 0;}
private:char title[50];int pages;
};int main() {Book novel;  // 創建對象時自動調用Book()構造函數return 0;
}

2. 構造函數分類

(1)無參構造函數(默認構造函數)
定義與特性
  • 無參數:函數括號內沒有參數列表。
  • 編譯器自動生成:若類中未定義任何構造函數,編譯器會生成一個空的默認構造函數(成員變量初始化為默認值,如數值為 0、指針為nullptr)。
  • 手動定義的必要性:若定義了其他帶參構造函數,編譯器不再自動生成默認構造函數,需手動定義以支持無參創建對象。
示例:手動定義默認構造函數
class Student {
public:// 顯式定義默認構造函數Student() {id = 0;name = "匿名";score = 0.0f;}
private:int id;std::string name;float score;
};Student stu;  // 調用默認構造函數,id=0,name="匿名",score=0.0f
(2)帶參構造函數
定義與作用
  • 包含參數:通過參數為成員變量賦初始值,支持靈活初始化。
  • 參數作用域:參數名可與成員變量同名,通過this指針區分(this->成員變量)。
示例:通過參數初始化成員
class Circle {
public:// 帶參構造函數:初始化半徑和面積Circle(float r) {radius = r;  // 成員變量radius = 參數rarea = 3.14f * r * r;  // 計算初始面積}
private:float radius;float area;
};Circle c(5.0f);  // 創建半徑5.0的圓,area自動計算為78.5
(3)初始化列表(Constructor Initializer List)
語法與格式
  • 位置:在構造函數參數列表后,使用:分隔,多個成員用逗號分隔。
  • 格式構造函數(參數列表) : 成員1(值1), 成員2(值2), ... { 函數體 }
核心優勢
  • 效率更高:直接調用成員的構造函數(如類成員對象),避免先默認構造再賦值。
  • 必需場景:初始化const成員或引用成員(二者必須在定義時初始化)。
示例:初始化列表的使用
class Person {
public:// 普通成員與const成員的初始化Person(std::string n, int a) : name(n), age(a) { // 函數體可空,初始化在列表完成}// 引用成員必須通過初始化列表賦值Person(std::string n, int a, int& ref) : name(n), age(a), ref_num(ref) { }
private:std::string name;int age;const int ref_num;  // const引用成員,必須在初始化列表賦值
};// 初始化const成員的錯誤與正確寫法對比
class ErrorDemo {const int value;
public:ErrorDemo() { value = 10; }  // 錯誤!const成員不能賦值
};class CorrectDemo {const int value;
public:CorrectDemo() : value(10) { }  // 正確!通過初始化列表賦值
};
(4)構造函數重載
重載規則
  • 函數名相同,但參數列表不同(參數個數、類型、順序至少有一個不同)。
  • 返回值類型無關:不能通過返回值區分重載構造函數。
示例:多種初始化方式
class Vector {
public:// 無參構造:初始化零向量Vector() : x(0), y(0) {}// 單參數構造:二維向量(x=y)Vector(float val) : x(val), y(val) {}// 雙參數構造:指定x和yVector(float x_val, float y_val) : x(x_val), y(y_val) {}
private:float x, y;
};// 調用不同構造函數
Vector v1;        // 無參構造,(0, 0)
Vector v2(5.0f);  // 單參構造,(5.0, 5.0)
Vector v3(3.0f, 4.0f);  // 雙參構造,(3.0, 4.0)
C++14 簡化寫法:= default
  • 作用:顯式讓編譯器生成默認構造函數,保持代碼簡潔。
  • 示例
    class Simple {
    public:Simple() = default;  // 等價于空的默認構造函數Simple(int x) : data(x) {}
    private:int data;
    };
    

3. 初始化 const 成員的強制要求

為什么必須用初始化列表?
  • const成員在聲明后不能被賦值(只能初始化),而構造函數的函數體執行時,成員變量已完成定義,無法再對const成員賦值。
  • 初始化列表在成員變量定義時直接賦值,滿足const的初始化要求。
示例:const 成員的正確初始化
class MathConstants {
public:// 初始化const成員PI和引用成員epsilon(引用必須初始化)MathConstants(float eps) : PI(3.14159f), epsilon(eps) {}
private:const float PI;  // 圓周率,固定值float& epsilon;  // 精度引用,必須在初始化列表賦值
};// 錯誤示例:試圖在函數體中賦值const成員
class ErrorCase {const int value;
public:ErrorCase(int v) { value = v; }  // 編譯錯誤!const成員不能賦值
};// 正確示例:通過初始化列表賦值
class CorrectCase {const int value;
public:CorrectCase(int v) : value(v) {}  // 正確
};

4. 構造函數的最佳實踐

(1)統一使用初始化列表
  • 無論是否為const成員,優先在初始化列表中賦值,提升效率(尤其對類成員對象)。
(2)避免冗余初始化
  • 若成員變量無需特殊處理,可依賴編譯器默認初始化(如std::string默認構造為空字符串)。
(3)處理動態資源
  • 在構造函數中分配資源(如new內存),并在析構函數中釋放(確保資源配對)。
    class DynamicArray {
    public:DynamicArray(int size) : data(new int[size]), length(size) {}~DynamicArray() { delete[] data; }  // 析構函數釋放內存
    private:int* data;int length;
    };
    

總結:構造函數核心知識點

特性說明
必需性創建對象時必須調用構造函數,編譯器自動生成默認構造函數(無其他構造函數時)。
初始化方式普通成員可在函數體賦值,const成員和引用成員必須通過初始化列表初始化。
重載規則參數列表不同(個數、類型、順序),支持靈活的對象創建方式。
資源管理構造函數分配資源,析構函數釋放資源,確保內存安全。

通過合理設計構造函數,開發者能確保對象在創建時處于有效狀態,為后續操作奠定基礎。下一節將深入解析析構函數與對象生命周期管理,進一步理解 C++ 對象的完整生命周期。

四、析構函數:對象的清理

在 C++ 中,對象的生命周期管理至關重要。構造函數負責對象的初始化,而析構函數則承擔著對象銷毀時的清理工作,確保資源正確釋放,避免內存泄漏。下面從基礎概念到實戰應用逐步解析析構函數的核心知識。

1. 析構函數概述

語法規則
  • 函數名:以~符號開頭,后跟類名(與構造函數對應),例如~ClassName()
  • 參數與返回值:沒有參數,也沒有返回值(不能寫void)。
  • 調用時機
    • 棧對象離開作用域時(如函數結束)。
    • 堆對象通過delete釋放時(如delete p;)。
    • 程序結束時(全局對象和靜態對象銷毀)。
核心作用
  • 資源釋放:釋放構造函數或成員函數分配的資源(如動態內存new、文件句柄fopen、網絡連接等)。
  • 數據清理:重置成員變量狀態,避免無效引用。
與構造函數的關系
  • 配對使用:構造函數分配資源,析構函數釋放資源,形成 “資源管理對”(RAII 模式的基礎)。
  • 執行順序:構造函數按 “基類→派生類” 順序執行,析構函數按 “派生類→基類” 逆序執行(確保派生類資源先釋放,基類后釋放)。

2. 示例:釋放動態內存(核心場景)

需求:管理動態數組的生命周期

當類中包含動態分配的內存(如new創建的數組),必須在析構函數中用delete釋放,否則會導致內存泄漏。

代碼實現
#include <iostream>
using namespace std;class DynamicArray {
private:int* data;   // 動態數組指針int size;    // 數組大小public:// 構造函數:分配內存并初始化DynamicArray(int s) : size(s) {data = new int[size];  // 分配size個int的內存空間for (int i = 0; i < size; i++) {data[i] = i;  // 初始化數組元素}cout << "構造函數:分配內存,地址=" << data << endl;}// 析構函數:釋放動態內存~DynamicArray() {delete[] data;  // 釋放數組內存(與new[]配對)data = nullptr; // 置空指針,避免野指針cout << "析構函數:釋放內存,地址=" << data << endl;}
};int main() {// 棧對象:離開main作用域時自動調用析構函數{DynamicArray arr(5);  // 構造函數執行,分配內存}  // 作用域結束,析構函數自動調用// 堆對象:顯式調用delete時觸發析構函數DynamicArray* ptr = new DynamicArray(3);  // 構造函數執行delete ptr;  // 手動釋放,析構函數調用return 0;
}
代碼解釋
  1. 構造函數

    • 接收參數size,使用new[]分配動態數組內存。
    • 初始化數組元素,輸出內存地址以便觀察。
  2. 析構函數

    • 使用delete[]釋放動態數組(必須與new[]配對,單個對象用delete)。
    • 釋放后將指針置為nullptr,防止后續誤操作(野指針問題)。
  3. 調用場景

    • 棧對象arr在離開花括號作用域時,自動調用析構函數。
    • 堆對象ptr通過delete顯式釋放,觸發析構函數。

3. 注意事項與進階知識

(1)默認析構函數:編譯器的 “隱形助手”
  • 自動生成條件:若用戶未定義析構函數,編譯器會生成一個默認析構函數(空函數)。
    class Simple {int value;  // 無自定義析構函數,編譯器生成~Simple() {}
    };
    
  • 局限性:默認析構函數僅能釋放非動態資源(如基本類型、標準庫對象),對new分配的內存、文件句柄等無效,需手動定義析構函數。
(2)析構函數與繼承:順序至關重要
  • 基類與派生類的執行順序

    1. 創建派生類對象時:先執行基類構造函數 → 再執行派生類構造函數。
    2. 銷毀派生類對象時:先執行派生類析構函數 → 再執行基類析構函數(與構造順序相反)。
    class Base {
    public:~Base() { cout << "Base析構" << endl; }
    };
    class Derived : public Base {
    public:~Derived() { cout << "Derived析構" << endl; }
    };int main() {Derived obj;  // 輸出:Base構造 → Derived構造(假設存在構造函數)// 銷毀時輸出:Derived析構 → Base析構return 0;
    }
    
(3)析構函數不能重載
  • 原因:析構函數沒有參數列表,無法通過參數區分不同版本,因此每個類最多有一個析構函數。
(4)析構函數與異常處理
  • 原則:析構函數中避免拋出異常,否則可能導致程序終止。
  • 處理方式:若必須處理異常,應在析構函數內部捕獲并處理,而非拋出。
    ~DynamicArray() {try {delete[] data;} catch (...) {// 處理異常或記錄日志}
    }
    

4. 最佳實踐:資源管理的黃金法則

(1)RAII 模式(資源獲取即初始化)
  • 核心思想:通過構造函數獲取資源,析構函數釋放資源,確保資源生命周期與對象綁定。
  • 典型應用
    • 動態內存:new/delete配對。
    • 文件操作:構造函數打開文件,析構函數關閉文件。
    class FileHandler {
    public:FileHandler(const char* path) {file = fopen(path, "r");  // 構造函數打開文件}~FileHandler() {if (file) fclose(file);  // 析構函數關閉文件}
    private:FILE* file;
    };
    
(2)避免手動管理資源:使用智能指針
  • C++11 引入std::unique_ptrstd::shared_ptr,自動管理動態內存,無需手動編寫析構函數。
    #include <memory>
    class ModernArray {
    private:std::unique_ptr<int[]> data;  // 智能指針自動釋放內存
    public:ModernArray(int size) : data(new int[size]) {}  // 無需析構函數
    };
    

總結:析構函數核心知識點

特性說明
語法特征~類名命名,無參數、無返回值,自動調用于對象銷毀時。
核心作用釋放動態資源(如new內存、文件句柄),防止內存泄漏。
默認行為未定義時編譯器生成空析構函數,僅適用于無動態資源的類。
繼承場景析構順序與構造順序相反(派生類→基類),確保資源正確釋放。
最佳實踐結合 RAII 模式,或使用智能指針簡化資源管理,避免手動編寫繁瑣析構邏輯。

通過合理設計析構函數,開發者能有效管理對象生命周期,確保程序的穩定性和資源利用率。下一節將深入探討this指針與靜態成員,進一步理解類的內部機制。

五、this 指針:指向當前對象的 “隱形指針”

1. this 指針作用

  • 解決命名沖突:當成員變量與參數同名時,用this->成員名區分。
    class Person {
    private:char name[20];int age;
    public:void set_name(char* name) {strcpy(this->name, name);  // this->name是成員變量,name是參數}
    };
    

2. 隱含參數

  • 成員函數隱式包含this指針參數,調用時自動傳遞當前對象地址。
    Person p;
    p.set_name("Alice");  // 等價于 set_name(&p, "Alice")
    

3. 返回當前對象引用(鏈式調用)

class Counter {
private:int value;
public:Counter& add(int n) {value += n;return *this;  // 返回當前對象引用}
};Counter c;
c.add(10).add(20);  // 鏈式調用,等價于 c.add(10); c.add(20);

六、靜態成員:類級別的共享數據與函數

1. 靜態成員變量

  • 定義:用static修飾,屬于類而非對象,所有對象共享。

  • 初始化:必須在類外初始化,格式為類型 類名::變量名 = 初始值;

    class Student {
    public:static int total_students;  // 聲明靜態成員變量
    };
    int Student::total_students = 0;  // 類外初始化
    
  • 訪問方式

    • 通過類名:Student::total_students
    • 通過對象:stu1.total_students(需公有權限)

2. 靜態成員函數

  • 特點:只能訪問靜態成員(變量 / 函數),無this指針。
  • 應用場景:統計類的對象數量。
    class Student {
    public:static int get_total() {  // 靜態成員函數return total_students;}
    };
    

七、const 成員:保護數據不被修改

1. const 成員變量

  • 初始化:必須通過構造函數初始化列表賦值,不可修改。
    class Math {
    private:const float PI;  // const成員變量
    public:Math() : PI(3.14f) {}  // 初始化列表賦值
    };
    

2. const 成員函數(常成員函數)

  • 語法:在函數聲明后加const,保證不修改成員變量。
    class Circle {
    private:float radius;
    public:float get_radius() const {  // 常成員函數return radius;  // 不可修改radius}
    };
    

3. const 對象

  • 定義const 類名 對象名;,只能調用常成員函數。
    const Circle c(5.0);
    c.get_radius();  // 合法,調用常成員函數
    // c.set_radius(6.0);  // 非法,set_radius非const函數
    

八、友元:打破訪問權限的 “特權”

在 C++ 中,類的封裝性通過public/protected/private嚴格控制成員訪問,但有時需要允許特定的函數或類突破這種限制,直接訪問私有成員。** 友元(Friend)** 機制就是為此設計的 “特權通道”,它允許非類成員函數或其他類的成員函數訪問當前類的私有 / 保護成員。

1. 友元函數

友元函數是獲得類訪問特權的非成員函數,分為兩種類型:全局非成員友元函數和其他類的成員友元函數。

(1)非成員友元函數
定義與聲明
  • 作用:允許一個全局函數(不屬于任何類)訪問類的私有 / 保護成員。
  • 聲明方式:在類體內用friend關鍵字聲明函數原型,格式為:
    friend 返回值類型 函數名(參數列表);  
    
  • 關鍵特性:友元函數不是類的成員,無需通過對象調用,但可訪問類的所有成員。
示例:訪問銀行賬戶余額(私有成員)
#include <iostream>  
using namespace std;  class BankAccount {  
private:  float balance;  // 私有成員:賬戶余額  public:  // 聲明全局函數display_balance為友元  friend void display_balance(const BankAccount& acc);  // 構造函數初始化余額  BankAccount(float bal) : balance(bal) {}  
};  // 友元函數定義:可直接訪問私有成員balance  
void display_balance(const BankAccount& acc) {  cout << "賬戶余額:" << acc.balance << " 元" << endl;  
}  int main() {  BankAccount account(10000.5f);  display_balance(account);  // 合法!友元函數訪問私有成員  return 0;  
}  
代碼解析
  • 友元聲明friend void display_balance(...)在類內聲明,賦予該函數訪問私有成員balance的權限。
  • 參數傳遞:使用const引用傳遞對象,避免拷貝構造,提高效率并防止修改原始對象。
(2)其他類的成員友元函數
應用場景

當類 B 的某個成員函數需要訪問類 A 的私有成員時,可將該成員函數聲明為類 A 的友元。

聲明方式
class A {  
private:  int private_data;  
public:  // 聲明類B的成員函數B::friend_func為友元  friend void B::friend_func(A& obj);  
};  class B {  
public:  void friend_func(A& obj) {  obj.private_data = 100;  // 合法!訪問A的私有成員  }  
};  
示例:類間協作訪問私有成員
#include <iostream>  
using namespace std;  class Teacher;  // 前向聲明,解決類依賴  class Student {  
private:  int student_id;  
public:  // 聲明Teacher類的成員函數Teacher::view_id為友元  friend void Teacher::view_id(Student& stu);  Student(int id) : student_id(id) {}  
};  class Teacher {  
public:  void view_id(Student& stu) {  cout << "學生ID:" << stu.student_id << endl;  // 訪問私有成員  }  
};  int main() {  Student stu(20230001);  Teacher teacher;  teacher.view_id(stu);  // 教師類成員函數訪問學生類私有ID  return 0;  
}  
注意事項
  • 前向聲明:若友元函數所屬的類未定義,需提前聲明(如class Teacher;),但不能訪問其成員細節。
  • 單向特權:僅被聲明的成員函數擁有訪問權,類 B 的其他成員函數仍無權限。

2. 友元類

定義與聲明
  • 作用:將整個類 B 聲明為類 A 的友元,類 B 的所有成員函數均可訪問類 A 的私有 / 保護成員。
  • 聲明方式:在類 A 內用friend class B;聲明類 B 為友元。
示例:友元類訪問私有成員
#include <iostream>  
using namespace std;  class Library;  // 前向聲明  class Book {  
private:  string title;  int page_count;  public:  Book(string t, int p) : title(t), page_count(p) {}  // 聲明Library為友元類  friend class Library;  
};  class Library {  
public:  void display_book_info(Book& b) {  // 訪問Book的私有成員  cout << "書名:" << b.title << ", 頁數:" << b.page_count << endl;  }  
};  int main() {  Book book("C++ Primer", 1000);  Library lib;  lib.display_book_info(book);  // 合法!友元類成員函數訪問私有成員  return 0;  
}  
友元類的特性
  1. 單向性

    • 若 A 是 B 的友元類,B 不一定是 A 的友元類,除非 A 也聲明 B 為友元。
    class A { friend class B; };  // A允許B訪問自己的私有成員  
    class B { friend class A; };  // 需額外聲明,B才允許A訪問自己的私有成員  
    
  2. 不可傳遞性

    • 若 B 是 A 的友元,C 是 B 的友元,C 并非自動成為 A 的友元。
  3. 破壞封裝性

    • 友元類可訪問所有私有成員,打破類的封裝邊界,需謹慎使用(僅在必要的類間協作時使用)。

3. 友元的優缺點與最佳實踐

(1)核心優勢
  • 靈活協作:允許類間高效交互,避免通過公有接口間接訪問(如性能敏感場景)。
  • 保留封裝性:僅對特定函數 / 類開放權限,而非完全公開私有成員。
(2)潛在風險
  • 耦合度增加:友元關系會強化類間依賴,修改一方可能影響另一方。
  • 調試難度:私有成員的訪問點分散在友元函數 / 類中,難以追蹤。
(3)使用建議
  1. 最小特權原則:優先聲明單個友元函數而非整個友元類,縮小特權范圍。
  2. 文檔說明:在友元聲明處注釋說明原因,提高代碼可讀性。
  3. 避免濫用:僅在必要時使用(如運算符重載、類間數據共享),優先通過公有接口實現。

總結:友元核心知識點

類型定義聲明方式訪問權限
非成員友元函數全局函數,通過friend聲明獲得類私有成員訪問權friend void func(類對象);可訪問類的所有成員(含私有)
成員友元函數其他類的成員函數,聲明后可訪問當前類私有成員friend void 類B::func(類A對象);僅該成員函數擁有訪問權
友元類整個類的所有成員函數可訪問當前類私有成員friend class 類B;類 B 的所有成員函數均有訪問權

友元機制是 C++ 封裝性的補充,合理使用能在保持代碼結構的同時實現高效交互。但需注意控制特權范圍,避免過度依賴,確保代碼的可維護性和安全性。下一章節將深入探討拷貝構造函數與對象復制,理解對象創建的深層機制。

九、拷貝構造函數:對象的 “復制粘貼”

1. 自定義拷貝構造函數

  • 語法:參數為當前類的const引用,避免遞歸調用。
    class String {
    private:char* str;
    public:String(char* s) {  // 普通構造函數str = new char[strlen(s)+1];strcpy(str, s);}String(const String& obj) {  // 拷貝構造函數str = new char[strlen(obj.str)+1];strcpy(str, obj.str);  // 深拷貝,避免淺拷貝問題}~String() { delete[] str; }
    };
    

2. 默認拷貝構造函數

  • 自動生成:若未定義,編譯器生成默認版本(淺拷貝),適用于無動態資源的類。
  • 風險:若類包含動態內存,默認拷貝會導致多個對象指向同一塊內存,釋放時崩潰。

3. 調用場景

  • 對象初始化:String s2 = s1;?或?String s2(s1);
  • 函數傳參:void func(String obj);?調用時復制實參對象。
  • 函數返回:String func() { String s; return s; }?返回時復制對象。

十、總結:類與對象核心知識點

概念關鍵特性
類的定義封裝數據與行為,通過public/protected/private控制訪問權限。
對象初始化構造函數(含參數、初始化列表、重載),自動調用,初始化成員數據。
資源管理析構函數釋放資源,避免內存泄漏,與構造函數成對出現。
數據共享靜態成員(變量 / 函數)屬于類,所有對象共享,類外初始化。
權限突破友元函數 / 類可訪問私有成員,打破封裝限制,需謹慎使用。
對象復制拷貝構造函數實現深拷貝,避免默認淺拷貝的內存問題。
類型安全const 成員保證數據不被修改,常對象僅能調用常成員函數。

通過以上知識點,我們掌握了 C++ 類與對象的核心機制,從封裝數據到管理對象生命周期,再到靈活處理對象間的關系。后續將深入學習繼承與多態,進一步體會面向對象編程的強大能力。

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

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

相關文章

嵌入式---電機分類

一、按電流類型分類&#xff08;最基礎分類&#xff09; 1. 直流電機&#xff08;DC Motor&#xff09; 工作原理&#xff1a;通過換向器&#xff08;有刷&#xff09;或電子換向&#xff08;無刷&#xff09;將直流電源轉換為交變磁場&#xff0c;驅動轉子旋轉。 核心特點&a…

【python】并行編程模塊:threading / mutliprocess / parallel / Celery

在并行編程中&#xff0c;Python 具有簡化實現的內置和外部模塊。 本書是基于Python3.X的。 Python的threading模塊 Python的threading模塊為模塊 _thread 提供了一個抽象層&#xff0c;它是一個較低級別的模塊。 它提供的功能可以幫助程序員完成基于線程開發并行系統的艱巨任…

OpengGL教程(七)---攝像機

本章參考官方教程&#xff1a;攝像機 本系列歷史文 OpengGL教程(一)—OpenGL環境的配置(GLFW3,GLAD) OpengGL教程(二)—渲染一個簡單的窗體 OpengGL教程(三)—使用VAO和VBO方式繪制三角形 OpengGL教程(四)—使用EBO方式繪制矩形 OpengGL教程(五)—紋理的應用 OpengGL教程(六)—…

安卓手機怎樣開啟雙WiFi加速

1. 小米/Redmi手機 路徑&#xff1a; 設置 → WLAN → 高級設置 → 雙WLAN加速 操作&#xff1a; 開啟功能后&#xff0c;可同時連接一個2.4GHz WiFi和一個5GHz WiFi&#xff08;或兩個不同路由器&#xff09;。 可選擇“智能選擇”或手動指定輔助網絡。 2. 華為/榮耀手機…

什么是八步工作法?

八步工作法&#xff0c;顧名思義&#xff0c;就是把一項工作拆分成八個步驟來完成。它的核心目的是讓工作變得更有條理&#xff0c;更高效&#xff0c;避免忙而無序&#xff0c;做到事事有著落&#xff0c;件件有結果。這個方法在很多企業和單位中都有應用&#xff0c;尤其適合…

前端Node.js的包管理工具npm指令

?npm&#xff08;Node Package Manager&#xff09;是Node.js的包管理工具&#xff0c;主要用于安裝、更新、刪除和管理JavaScript包。以下是前端開發中常用的npm命令及其用途?&#xff1a; 基本命令 npm提供了一系列命令行工具&#xff0c;用于執行各種包管理操作。以下是一…

掌握C語言文件操作:從理論到實戰指南

文件操作是C語言編程中不可或缺的一部分&#xff0c;它使得程序能夠持久化存儲數據&#xff0c;并在需要時高效讀寫。本文將從基礎概念到實戰技巧&#xff0c;系統講解C語言文件操作的核心知識點&#xff0c;并結合代碼示例幫助讀者深入理解。 一. 為什么需要文件操作&#xf…

Linux 線程:從零構建多線程應用:系統化解析線程API與底層設計邏輯

線程 線程的概述 在之前&#xff0c;我們常把進程定義為 程序執行的實例&#xff0c;實際不然&#xff0c;進程實際上只是維護應用程序的各種資源&#xff0c;并不執行什么。真正執行具體任務的是線程。 那為什么之前直接執行a.out的時候&#xff0c;沒有這種感受呢&#xf…

014_多線程

多線程 多線程創建線程方式一&#xff1a;繼承Thread類方式二&#xff1a;實現Runable接口方式三&#xff1a;實現Callbale接口 Thread的常用方法線程安全線程同步方式一&#xff1a;同步代碼塊同步方法方式三&#xff1a;Lock鎖 線性池創建線程池處理Runnable任務處理Callable…

機場跑道異物檢測數據集VOC+YOLO格式33793張31類別

數據集分辨率都是300x300,都是貼近地面拍攝&#xff0c;具體看圖片 據集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路徑的txt文件&#xff0c;僅僅包含jpg圖片以及對應的VOC格式xml文件和yolo格式txt文件) 圖片數量(jpg文件個數)&#xff1a;33793 標注數量(xml文件…

Spring Cloud 遠程調用

4.OpenFeign的實現原理是什么&#xff1f; 在使用OpenFeign的時候&#xff0c;主要關心兩個注解&#xff0c;EnableFeignClients和FeignClient。整體的流程分為以下幾個部分&#xff1a; 啟用Feign代理&#xff0c;通過在啟動類上添加EnableFeignClients注解&#xff0c;開啟F…

Unity中使用FMETP STREAM傳輸實時畫面

一、客戶端&#xff08;發送端&#xff09; 總體思路&#xff1a;先把畫面編碼Encoder&#xff0c;再發送給服務端 新建場景&#xff0c;創建一個實體&#xff0c;名為FMnet&#xff0c;添加組件FMNetworkManager&#xff0c;將NetworkType設置為客戶端Client&#xff0c;設置…

Baklib三步構建企業內容中臺

需求調研構建內容中臺 企業內容中臺建設的首要環節在于精準識別業務需求與知識管理痛點。通過Baklib 是什么類型的工具的定位分析可知&#xff0c;其作為知識管理中樞&#xff0c;能夠系統梳理客戶服務場景中的高頻咨詢、產品文檔更新需求及跨部門協作流程。在需求調研階段&am…

實現抗隱私泄漏的AI人工智能推理

目錄 什么是私人AI? 什么是可信執行環境? TEE 如何在 AI 推理期間保護數據? 使用 TEE 是否存在風險? 有哪些風險? Atoma 如何應對這些風險 為什么去中心化網絡是解決方案 人工智能推理過程中還有其他保護隱私的方法嗎? 私人人工智能可以實現什么? 隱私驅動的應…

一、TorchRec里邊的輸入輸出類型

TorchRec中的輸入和輸出格式 文章目錄 TorchRec中的輸入和輸出格式前言一、JaggedTensor1.1 核心概念1.2 核心屬性&#xff0c;也就是參數1.3 關鍵操作與方法 二、KeyedJaggedTensor2.1 核心概念2.2 核心屬性&#xff0c;也就是參數 3、KeyedTensor總結 前言 TorchRec具有其特…

JAVA實現在H5頁面中點擊鏈接直接進入微信小程序

在普通的Html5頁面中如何實現點擊URL鏈接直接進入微信小程序&#xff0c;不需要掃描小程序二維碼&#xff1f; 網上介紹的很多方法是在小程序后臺設置Schema&#xff0c;不過我進入我的小程序后臺在開發設置里面 沒有找到設置小程序Schema的地方&#xff0c;我是通過調用API接口…

uniapp解決上架華為應用市場審核要求-監聽權限的申請

支持android平臺全局監聽權限的申請。當申請權限時&#xff0c;會在頁面頂部顯示申請權限的目的。主要解決上架華為應用市場審核要求&#xff1a;APP在調用終端權限時&#xff0c;應同步告知用戶申請該權限的目的。 因為如果不提示&#xff0c;你上架應用市場會被打打回來 Tip…

文件IO5(JPEG圖像原理與應用)

JPEG圖像原理與應用 ? 基本概念 JPEG&#xff08;Joint Photographic Experts Group&#xff09;指的是聯合圖像專家組&#xff0c;是國際標準化組織ISO制訂并于1992年發布的一種面向連續色調靜止圖像的壓縮編碼標準&#xff0c;所以也被稱為JPEG標準。 同樣&#xff0c;JP…

vue3 history路由模式刷新頁面報錯問題解決

在使用history路由模式時刷新網頁提示404錯誤&#xff0c;這是改怎么辦呢。 官方解決辦法 https://router.vuejs.org/zh/guide/essentials/history-mode.html

3D激光輪廓儀知識整理(待完善)

文章目錄 1.原理和應用場景1.1 相機原理1.1.1 測量原理1.1.2 相機激光器1.1.3 沙姆鏡頭1.1.4 相機標定1.1.5 中心線提取 1.2 應用場景1.2.1 測量相關應用1.2.2 缺陷檢測相關應用 2.相機參數介紹及選型介紹2.1 成像原理2.2 原始圖成像2.3 生成輪廓圖2.4 相機規格參數2.4.1 單輪廓…