C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++ private、protected、public

C++ private、protected、public从入门到精通实例解析

作者:带土1

本文介绍了C++中的访问控制关键字public、protected和private,包括它们的定义、规则和应用场景,同时,还探讨了继承中的访问控制以及友元的概念和使用,文章还提供了面试高频考点的标准答案,并总结了开发中最佳实践,感兴趣的朋友跟随小编一起看看吧

八股文又来了, 看吧 看一遍你就会了 时间长忘了?那就再看一遍孩子

一、核心概述

privateprotectedpublic 是 C++ 封装特性的核心载体,其本质是在编译期限制类成员(变量/函数)在不同作用域下的可见性和访问权限——简单来说,就是规定“哪些地方能使用类的某个成员,哪些地方不能”。掌握这三个关键字的规则,是写出符合工程化规范、高内聚低耦合 C++ 代码的基础。

二、基础定义 & 核心访问规则

2.1 核心规则表(必记)

关键字官方定义大白话解释类内访问类外访问(通过对象)派生类(子类)访问
public公有的,对外暴露的接口,无访问限制谁都能访问:类自己能用、外部代码能用、子类也能用✅ 允许✅ 允许✅ 允许
private私有的,仅类内部可见,封装的核心体现只有类自己能用:外部代码不能用、子类也不能用(友元除外)✅ 允许❌ 禁止❌ 禁止
protected受保护的,介于public和private之间,为派生类预留的访问权限类自己能用、子类能用,但外部代码不能用✅ 允许❌ 禁止✅ 允许

2.2 默认访问控制(易错点)

2.3 基础验证代码

#include <iostream>
using namespace std;
class MyClass {
    // 未写关键字,class默认private
    int default_val = 0; 
public:
    int pub_val = 10;    // 公有成员
    void pub_func() {
        // 类内:能访问所有成员(public/private/protected)
        cout << "类内访问 private_val: " << pri_val << endl;
        cout << "类内访问 protected_val: " << pro_val << endl;
        cout << "类内访问 default_val: " << default_val << endl;
    }
private:
    int pri_val = 20;    // 私有成员
    void pri_func() { cout << "私有函数" << endl; }
protected:
    int pro_val = 30;    // 受保护成员
    void pro_func() { cout << "受保护函数" << endl; }
};
// 派生类(子类)
class Derived : public MyClass {
public:
    void derived_func() {
        // 派生类:能访问基类的public/protected,不能访问private
        cout << "派生类访问 pub_val: " << pub_val << endl;       // ✅ 允许
        cout << "派生类访问 pro_val: " << pro_val << endl;       // ✅ 允许
        // cout << "派生类访问 pri_val: " << pri_val << endl;    // ❌ 禁止:private不可访问
        pro_func();                                             // ✅ 允许调用protected函数
        // pri_func();                                          // ❌ 禁止调用private函数
    }
};
int main() {
    MyClass obj;
    // 类外:仅能访问public成员
    cout << "类外访问 pub_val: " << obj.pub_val << endl;         // ✅ 允许
    // cout << "类外访问 pro_val: " << obj.pro_val << endl;     // ❌ 禁止:protected不可访问
    // cout << "类外访问 pri_val: " << obj.pri_val << endl;     // ❌ 禁止:private不可访问
    obj.pub_func();                                             // ✅ 允许调用public函数
    // obj.pro_func();                                          // ❌ 禁止调用protected函数
    // obj.pri_func();                                          // ❌ 禁止调用private函数
    Derived d_obj;
    d_obj.derived_func();                                       // ✅ 派生类内部逻辑正常执行
    return 0;
}

2.4 补充:同一类不同对象的访问规则

访问控制是“类级别”的限制,而非“对象级别”——同一个类的不同对象,可互相访问对方的 private/protected 成员(编译期认为属于“同一类的内部”):

#include <iostream>
using namespace std;
class MyClass {
private:
    int m_val = 10;
public:
    // 访问同类型另一个对象的private成员
    void accessAnotherObj(MyClass& other) {
        cout << "访问另一个对象的private成员:" << other.m_val << endl; // ✅ 允许
        other.m_val = 20; // ✅ 可修改
    }
    int getVal() const { return m_val; }
};
int main() {
    MyClass a, b;
    a.accessAnotherObj(b); // 输出:访问另一个对象的private成员:10
    cout << "修改后b的val:" << b.getVal() << endl; // 输出:20
    return 0;
}

三、继承中的访问控制(面试必考)

派生类继承基类时,继承方式(public/protected/private) 会修改“基类成员在派生类中的访问权限”,核心铁律:

派生类对基类成员的访问权限 = 「基类成员自身的访问权限」和「继承方式」中更严格的那个。

3.1 继承权限影响表

基类成员访问权限public继承(最常用)protected继承private继承
publicpublic(不变)protectedprivate
protectedprotected(不变)protectedprivate
private不可访问(不变)不可访问不可访问

3.2 单层继承代码示例

#include <iostream>
using namespace std;
// 基类
class Base {
public:
    int pub_val = 1;
protected:
    int pro_val = 2;
private:
    int pri_val = 3;
};
// 1. public继承(开发中99%的场景,推荐)
class DerivedPub : public Base {
public:
    void show() {
        cout << "pub_val: " << pub_val << endl;  // ✅ public → public
        cout << "pro_val: " << pro_val << endl;  // ✅ protected → protected
        // cout << pri_val << endl;              // ❌ 始终不可访问
    }
};
// 2. protected继承
class DerivedPro : protected Base {
public:
    void show() {
        cout << "pub_val: " << pub_val << endl;  // ✅ public → protected
        cout << "pro_val: " << pro_val << endl;  // ✅ protected → protected
    }
};
// 3. private继承
class DerivedPri : private Base {
public:
    void show() {
        cout << "pub_val: " << pub_val << endl;  // ✅ public → private
        cout << "pro_val: " << pro_val << endl;  // ✅ protected → private
    }
};
int main() {
    DerivedPub d_pub;
    cout << d_pub.pub_val << endl;  // ✅ public继承后,基类public仍为public,类外可访问
    // cout << d_pub.pro_val << endl; // ❌ protected,类外不可访问
    DerivedPro d_pro;
    // cout << d_pro.pub_val << endl; // ❌ public继承后变为protected,类外不可访问
    DerivedPri d_pri;
    // cout << d_pri.pub_val << endl; // ❌ public继承后变为private,类外不可访问
    return 0;
}

3.3 多层继承的权限链式影响

多层继承中,基类成员权限会随继承链“层层收紧”(仅会更严格,不会放宽):

#include <iostream>
using namespace std;
// 顶层基类
class A {
public:
    int pub_a = 1;
protected:
    int pro_a = 2;
};
// 第二层:B public继承A
class B : public A {
public:
    void showB() {
        cout << "B中访问A的pub_a:" << pub_a << endl; // ✅ public→public
        cout << "B中访问A的pro_a:" << pro_a << endl; // ✅ protected→protected
    }
};
// 第三层:C protected继承B
class C : protected B {
public:
    void showC() {
        // A的pub_a:A→B(public)→C(protected)→ 最终C中是protected
        cout << "C中访问A的pub_a:" << pub_a << endl; // ✅ 允许(C内可访问protected)
        // A的pro_a:A→B(protected)→C(protected)→ 最终C中是protected
        cout << "C中访问A的pro_a:" << pro_a << endl; // ✅ 允许
    }
};
// 第四层:D private继承C
class D : private C {
public:
    void showD() {
        // A的pub_a:经过三层继承后变为private
        cout << "D中访问A的pub_a:" << pub_a << endl; // ✅ D内可访问private
    }
};
int main() {
    C c;
    // cout << c.pub_a << endl; // ❌ C中pub_a是protected,类外不可访问
    D d;
    // cout << d.pub_a << endl; // ❌ D中pub_a是private,类外不可访问
    return 0;
}

四、特殊场景的访问控制细节

4.1 静态成员的访问控制

static 仅改变成员的“存储方式”(属于类而非对象),访问控制规则与普通成员完全一致

#include <iostream>
using namespace std;
class MyClass {
private:
    static int s_pri_val; // 静态私有成员
protected:
    static int s_pro_val; // 静态受保护成员
public:
    static int s_pub_val; // 静态公有成员
    static void showStatic() {
        // 类内可访问所有静态成员
        cout << "静态私有:" << s_pri_val << endl;
        cout << "静态受保护:" << s_pro_val << endl;
    }
};
// 静态成员必须类外初始化
int MyClass::s_pri_val = 10;
int MyClass::s_pro_val = 20;
int MyClass::s_pub_val = 30;
// 派生类
class Derived : public MyClass {
public:
    static void showDerivedStatic() {
        // 派生类可访问基类的static protected/public
        cout << "派生类访问静态受保护:" << s_pro_val << endl; // ✅
        cout << "派生类访问静态公有:" << s_pub_val << endl;   // ✅
        // cout << s_pri_val << endl; // ❌ 静态私有仍不可访问
    }
};
int main() {
    // 类外仅能访问静态公有成员
    cout << MyClass::s_pub_val << endl; // ✅ 30
    // cout << MyClass::s_pro_val << endl; // ❌ 静态受保护,类外不可访问
    // cout << MyClass::s_pri_val << endl; // ❌ 静态私有,类外不可访问
    Derived::showDerivedStatic(); // ✅ 派生类内可访问静态受保护
    return 0;
}

4.2 protected 的深层细节(易踩坑)

protected 允许“子类访问自己的基类成员”,但禁止子类访问其他子类对象的基类 protected 成员

#include <iostream>
using namespace std;
class Base {
protected:
    int m_val = 10;
};
class DerivedA : public Base {
public:
    // 错误场景:DerivedA试图访问DerivedB对象的protected成员
    void accessDerivedB(DerivedB& b) {
        // cout << b.m_val << endl; // ❌ 禁止:不能访问其他子类对象的protected
    }
    // 正确场景:访问自己的protected成员
    void accessSelf() {
        cout << m_val << endl; // ✅ 允许
    }
};
class DerivedB : public Base {}; // 另一个子类
int main() {
    DerivedA a;
    DerivedB b;
    a.accessSelf(); // ✅ 输出10
    // a.accessDerivedB(b); // ❌ 编译报错
    return 0;
}

五、友元:突破访问控制的唯一机制

friend 是 C++ 中唯一能突破 private/protected 访问限制的语法,核心是“显式授权”——只有被类主动声明为友元的函数/类,才能访问其私有/受保护成员。友元按授权粒度从粗到细分为以下三种形式:

5.1 友元函数(单个函数授权)

友元函数是最基础的友元形式,授权单个普通函数访问类的私有/受保护成员,适用于“仅需一个外部函数访问类内部数据”的场景(如运算符重载、简单的外部工具函数)。

#include <iostream>
using namespace std;
class MyClass {
private:
    int pri_val = 100;
    // 声明友元函数:仅授权showPrivate函数访问当前类的私有成员
    friend void showPrivate(MyClass& obj);
};
// 友元函数:可以直接访问MyClass的private成员(无需通过public接口)
void showPrivate(MyClass& obj) {
    cout << "访问private成员: " << obj.pri_val << endl; // ✅ 允许
}
int main() {
    MyClass obj;
    showPrivate(obj); // 输出:访问private成员: 100
    return 0;
}

核心总结

5.2 友元类(批量授权,整个类的所有成员函数)

友元类是“批量授权”形式,授权另一个类的所有成员函数(无论 public/private/protected)访问当前类的私有/受保护成员,适用于“两个类高度耦合且需要深度协作”的场景(如容器类和其迭代器类)。

#include <iostream>
using namespace std;
class A {
    // 声明B为友元类:B的所有成员函数都能访问A的私有/受保护成员
    friend class B; 
private:
    int m_val = 100;
};
class B {
public:
    // B的公有成员函数:访问A的私有成员
    void accessA(A& a) {
        cout << a.m_val << endl; // ✅ 允许
    }
private:
    // B的私有成员函数:同样能访问A的私有成员(友元类的所有成员函数都有权限)
    void privateAccessA(A& a) {
        a.m_val = 200; // ✅ 允许修改
    }
};
int main() {
    A a;
    B b;
    b.accessA(a); // 输出:100
    return 0;
}

核心总结

5.3 友元成员函数(精细授权,仅单个成员函数)

友元成员函数是“精准授权”形式,仅授权另一个类的某个特定成员函数访问当前类的私有/受保护成员,是兼顾“协作需求”和“封装性”的最优友元形式。

#include <iostream>
using namespace std;
// 前置声明:必须先声明A,才能在B的成员函数参数中使用A的引用
class A;
class B {
public:
    // 先声明需要授权的成员函数(仅该函数需要访问A的私有成员)
    void onlyThisFuncCanAccessA(A& a); 
};
class A {
    // 仅授权B类的onlyThisFuncCanAccessA成员函数访问当前类的私有成员
    friend void B::onlyThisFuncCanAccessA(A& a);
private:
    int m_val = 500;
};
// 实现授权的成员函数:可直接访问A的私有成员
void B::onlyThisFuncCanAccessA(A& a) {
    cout << a.m_val << endl; // ✅ 允许
}
int main() {
    A a;
    B b;
    b.onlyThisFuncCanAccessA(a); // 输出:500
    return 0;
}

核心总结

5.4 友元的核心特性(所有友元形式通用)

友元关系的核心规则不受授权形式影响,需牢记以下三点:

六、实际开发中的应用场景 & 反模式

6.1 核心应用场景(最佳实践)

关键字核心应用场景示例
public对外提供的「接口」(稳定、不轻易修改)业务方法(如 calculate())、get/set函数(如 getName()/setName()
private类的「内部实现细节」(隐藏,避免外部篡改)成员变量(如 m_name)、内部辅助函数(如 checkValid()
protected基类中需要给「派生类复用」,但不希望外部访问的成员基类的通用属性(如 m_id)、通用方法(如 initData()

6.2 常见反模式(严禁使用)

反模式1:成员变量设为 public

// 错误
class Student {
public:
    int m_age; // 外部可直接赋值 m_age = -5,数据完全不安全
};
// 正确
class Student {
private:
    int m_age;
public:
    void setAge(int age) {
        if (age >= 0 && age <= 120) m_age = age; // 带校验的写接口
    }
    int getAge() const { return m_age; } // 只读接口
};

反模式2:为方便将 protected 改为 public

// 错误
class Base {
public:
    int m_id; // 本应给子类复用的成员,被外部随意修改
};
// 正确
class Base {
protected:
    int m_id;
public:
    int getId() const { return m_id; } // 仅暴露只读接口
};

反模式3:过度使用友元,破坏封装

// 错误:授权多个类/函数,封装形同虚设
class A {
    friend class B;
    friend class C;
    friend void func1();
    friend void func2();
private:
    int m_data;
};
// 正确:仅授权必要的函数/类
class A {
    friend void onlyNecessaryFunc(A& a);
private:
    int m_data;
};

七、常见误区 & 避坑点

  1. 误区1protected 是“派生类的 private”→ 派生类之间不能访问对方的 protected 成员;
  2. 误区2:继承方式会修改基类自身的成员权限 → 仅修改“基类成员在派生类中的权限”,基类自身权限不变;
  3. 误区3static 会改变访问控制 → static private 仍仅类内可访问,static 不影响权限;
  4. 误区4:访问控制针对“对象”→ 同一类的不同对象可互相访问 private 成员(类级别限制);
  5. 误区5private 绝对不可访问 → 友元是合法途径,指针强制转换是不规范黑科技,严禁使用;
  6. 误区6struct 没有访问控制 → struct 只是默认权限为 public,同样支持 private/protected

八、面试高频考点 & 标准答案

8.1 基础考点

  1. classstruct 的访问控制默认值有什么区别?
    class 默认访问控制是 privatestruct 默认是 public(C++ 对 C 的兼容设计,struct 保留 C 的特性);
  2. protectedprivate 的核心区别是什么?
    :核心区别在派生类的访问权限 —— protected 允许派生类访问,private 不允许;类外两者都不可访问;
  3. :public 继承和 private 继承的核心区别?
    :public 继承保留基类 public 成员的公有属性(类外可访问),private 继承会把基类所有可访问成员变为 private(仅派生类内可访问);开发中优先用 public 继承;
  4. :友元是否受访问控制限制?
    :不受,友元函数/友元类可直接访问类的 private/protected 成员,是访问控制的合法例外。

8.2 进阶考点(结合多态)

:为什么私有虚函数能被派生类重写?

#include <iostream>
using namespace std;
class Base {
private:
    virtual void func() { cout << "Base::func" << endl; }
public:
    void callFunc() { func(); } // 公有接口调用私有虚函数
};
class Derived : public Base {
private:
    void func() override { cout << "Derived::func" << endl; }
};
int main() {
    Base* ptr = new Derived();
    ptr->callFunc(); // 输出:Derived::func
    delete ptr;
    return 0;
}

:访问控制(private)和多态(虚函数)是两个独立的机制:

九、核心总结

  1. 访问控制的本质是控制类成员的可见性,是编译期语法检查,核心为封装性服务;
  2. 基础规则:public(类内/外/派生类)、private(仅类内+友元)、protected(类内+派生类);
  3. 继承中:派生类对基类成员的权限 = 「基类成员权限」和「继承方式」中更严格的那个,private 成员始终不可访问;
  4. 特殊细节:同一类的不同对象可互相访问 private 成员,protected 仅允许子类访问自身的基类成员;
  5. 友元是唯一突破访问控制的机制,遵循“单向、不传递、不继承”,优先用“友元成员函数”最小化授权;
  6. 开发最佳实践:public 做接口、private 藏实现、protected 给子类复用,严禁 public 成员变量和过度友元。

到此这篇关于C++ private、protected、public从入门到精通实例解析的文章就介绍到这了,更多相关C++ private、protected、public内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文