【C++】“内部”、“外部”、“派生类”、“友元“类

在 C++ 的访问控制体系中,"内部"、"外部"、"派生类"、"友元"是判断成员能否被访问的四个关键上下文。下面结合 public、private、protected 三个访问控制符,逐一解释它们的含义与交互规则。

四个访问上下文的定义

  1. 内部(当前类/结构体内部)

    指当前类的成员函数、静态成员函数、友元函数,以及类模板的特化实现内部。

    • 无论成员是 public、protected 还是 private,内部代码均可访问。

    • 示例:

      cpp 复制代码
      class Base {
      private:
          int priv;
      protected:
          int prot;
      public:
          int pub;
          void func() {
              priv = 1;  // ✅ 内部可访问 private
              prot = 2;  // ✅ 内部可访问 protected
              pub = 3;   // ✅ 内部可访问 public
          }
      };
  2. 外部(类外部的普通代码)

    指不属于该类、其派生类或友元的普通函数、其他类的成员函数等。

    • 仅能访问 public 成员。

    • 示例:

      cpp 复制代码
      void external() {
          Base obj;
          obj.pub = 10;   // ✅ 外部可访问 public
          // obj.prot = 20; // ❌ 编译错误:protected 不可外部访问
          // obj.priv = 30; // ❌ 编译错误:private 不可外部访问
      }
  3. 派生类(继承自当前类的子类)

    指通过继承关系获得的子类,其成员函数和静态成员。

    • 可访问基类的 public 和 protected 成员。

    • 不可访问基类的 private 成员(即使通过继承,private 成员在派生类中仍存在但不可见)。

    • 注意:继承方式(public/protected/private 继承)会影响基类成员在派生类中的"可见访问级别",但不改变其原始声明的访问属性。

    • 示例:

      cpp 复制代码
      class Derived : public Base {
      public:
          void accessBase() {
              pub = 1;    // ✅ 可访问基类 public
              prot = 2;   // ✅ 可访问基类 protected
              // priv = 3; // ❌ 编译错误:基类 private 不可访问
          }
      };
  4. 友元(friend)

    通过 friend 关键字显式授权的函数或类,可突破访问控制限制。

    • 友元不是继承关系,也不受继承方式影响。

    • 友元可访问该类的所有成员(包括 private 和 protected)。

    • 友元关系不可传递、不可继承。

    • 示例:

      cpp 复制代码
      class Friend;  // 前向声明
      
      class Base {
      private:
          int priv;
      protected:
          int prot;
      public:
          int pub;
          // 声明友元函数
          friend void friendFunc(Base&);
          // 声明友元类
          friend class Friend;
      };
      
      void friendFunc(Base& obj) {
          obj.priv = 100;  // ✅ 友元函数可访问 private
          obj.prot = 200;  // ✅ 友元函数可访问 protected
          obj.pub = 300;   // ✅ 友元函数可访问 public
      }
      
      class Friend {
      public:
          void modify(Base& obj) {
              obj.priv = 10;  // ✅ 友元类成员可访问 Base 的 private
          }
      };

访问权限速查表

访问上下文 public protected private
内部(本类成员/静态/友元)
外部(普通代码)
派生类成员函数
友元函数/类

关键补充说明

  1. protected 的"继承可见性"细节

    • protected 成员在派生类中可访问,但仅限于通过派生类对象自身的 this 指针访问。
    • 不能通过基类指针/引用访问其他对象的 protected 成员(即使该对象是派生类实例)。
    cpp 复制代码
    class Base {
    protected:
        int val;
    };
    class Derived : public Base {
    public:
        void test(Derived& other, Base& baseRef) {
            val = 1;           // ✅ 访问自己的 protected
            other.val = 2;     // ✅ 访问同类型派生类对象的 protected
            // baseRef.val = 3; // ❌ 编译错误:不能通过基类引用访问其他对象的 protected
        }
    };
  2. 继承方式对成员"可见级别"的影响

    继承方式会"降级"基类成员在派生类接口中的访问级别,但不改变其原始声明属性:

    cpp 复制代码
    class Base {
    public: int pub;
    protected: int prot;
    private: int priv;
    };
    
    // public 继承:保持原级别
    class PubDer : public Base {
        // pub → public, prot → protected, priv → 不可见
    };
    
    // protected 继承:public/protected 都变为 protected
    class ProtDer : protected Base {
        // pub → protected, prot → protected, priv → 不可见
    };
    
    // private 继承:public/protected 都变为 private
    class PrivDer : private Base {
        // pub → private, prot → private, priv → 不可见
    };
  3. 友元的单向性与非传递性

    • A 声明 B 为友元,不代表 B 自动将 A 视为友元。
    • A 的友元不能自动访问 A 的派生类的 private 成员(除非派生类也显式声明该友元)。

理解这四个上下文与三种访问控制符的组合关系,是掌握 C++ 封装、继承与多态机制的基础。如有具体代码场景或设计困惑,可进一步提供细节进行分析。

相关推荐
王老师青少年编程2 小时前
2025年【江苏“信息与未来”编程思维】真题及题解(T2:坐标变换)
c++·题解·真题·坐标变换·编程思维·江苏·信息与未来
折哥的程序人生 · 物流技术专研2 小时前
第4篇:Lambda 简化策略模式(Java 8+)
java·设计模式·策略模式·函数式编程·lambda·代码简化·扩充系列
researcher-Jiang3 小时前
高性能计算之OpenMP——超算习堂学习1
android·java·学习
西门吹-禅4 小时前
java springboot N+1问题
java·开发语言·spring boot
DLYSB_5 小时前
生命通道:如何用 HIS 医疗系统直连网络声光终端,打造“零延误”的危急值响应网关?
java·网络·数据库·报警灯
skywalk81635 小时前
设计并实现段言的 C FFI 绑定机制 @Trae
c语言·开发语言·python·编程
weixin_BYSJ19875 小时前
SpringBoot + MySQL 乒乓球运动员信息管理系统项目实战--附源码04954
java·javascript·spring boot·python·django·flask·php
AI小码5 小时前
LLM 应用的缓存工程:当每次 API 调用都在燃烧成本
java·人工智能·spring·计算机·llm·编程·api
2023自学中6 小时前
C++ 内存追踪器
linux·c++
Hui Baby6 小时前
Spring Security
java·后端·spring