首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 存取控制本質:按類而非按對象 —— 深度解析與實例驗證

     編輯:關於C++

核心法則

C++ 存取控制基於類 (per-class),而非基於對象 (per-object)。

即:private/protected 成員對同類的所有對象可見,不僅限於 this 對象。

經典困惑:拷貝構造函數為何能訪問另一對象的 private?

class Trivial {
private:
    int val;
public:
    Trivial(const Trivial& other) {
        val = other.val; // ✅ 合法!other 是同類對象
    }
};

若存取控制是 per-object,other.val 應被禁止。實際編譯通過,證明是 per-class。

更深層驗證:派生類訪問基類 protected

class Base {
protected:
    int val;
};

class Derived : public Base {
public:
    void func(Base* b, Derived* d) {
        // b->val;  // ❌ 編譯錯誤:b 是 Base*,非 Derived 類內
        d->val;      // ✅ 合法:d 是 Derived*,Derived 類內可訪問 Derived 對象的 protected
        val;         // ✅ 合法:當前對象 (this) 的 protected
    }
};

錯誤分析

  • b->val 錯誤:當前代碼在 Derived 類內,但 b 的靜態類型是 Base*。存取檢查基於訪問代碼所在的類 (Derived) 和被訪問成員聲明的類 (Base)。Derived 只能訪問 Derived 及其基類中對 Derived 可見的成員,但只能通過 Derived 類型的表達式 (包括 this、Derived*、Derived&) 訪問。Base* 表達式不屬於 Derived 類型,故被拒。
  • d->val 合法:d 類型為 Derived*,屬於 Derived 類型表達式。
  • val 合法:隱式 this->val,this 為 Derived*。

Stack Overflow 經典解釋

In C++ access control works on per-class basis, not on per-object basis.
So an instance of class B will always have access to all the members of another instance of class B.

驗證代碼

#include <iostream>
#include <string>

class MyClass {
public:
    MyClass(const std::string& data) : mData(data) {}
    const std::string& getData(const MyClass& instance) const {
        return instance.mData; // ✅ 訪問另一對象的 private
    }
private:
    std::string mData;
};

int main() {
    MyClass a("Stack");
    MyClass b("Overflow");
    std::cout << "b via a = " << a.getData(b) << std::endl; // 輸出 Overflow
    return 0;
}

標準條文依據

C++17 [class.access] p1:

A member of a class can be accessed ... if the access is from a member or friend of the class ...

關鍵在於 from a member ... of the class —— 判斷依據是訪問代碼所在的類,而非對象身份。

實戰影響

場景per-object 直覺per-class 事實
拷貝/移動構造無法讀取源對象 private✅ 正常讀取
operator== 比較無法比較另一對象 private✅ 正常比較
容器內部操作迭代器無法訪問節點 private✅ 友元/成員函數正常訪問
派生類訪問基類 protected可通過基類指針訪問❌ 僅限派生類類型表達式

設計建議

  1. 理解 per-class 語義,大膽在成員函數中訪問同類其他對象的私有成員
  2. 派生類中訪問基類 protected 成員時,必須通過派生類類型的指針/引用/this
  3. 若需跨類訪問,使用 friend 或提供公有/保護接口
  4. 單例模式、工廠模式常利用 per-class 訪問私有構造函數

總結

「存取控制是類的屬性,不是對象的屬性」—— 這句話揭示了 C++ 封裝機制的本質:封裝邊界在類之間,不在對象之間。同一類的所有實例互為「自己人」,共享完整訪問權限。這設計既符合直覺 (同類對象協作無障礙),又保證了封裝的語義完整性 (外部類無法隨意侵入)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved