C++ 命名空间、虚函数、抽象类、protected 权限全套通俗易懂精讲(附与 Java 对比)

前言

初学 C++ 面向对象时,很多人会被这几个概念绕晕:

为什么要写两层 namespace?虚函数到底解决什么问题?虚函数和抽象类、纯虚函数什么关系?protected 权限怎么用?为什么工程里虚函数常放 protected?和 Java 的接口、抽象类又有什么区别?

今天用大白话 + 实战规范 + Java 横向对比,一次性全部梳理清楚,看完直接能用于项目开发和面试。

一、为什么 C++ 要写两层 namespace?

1. 什么是两层 namespace

示例代码:

cpp 复制代码
namespace myproject {        
    namespace core {  
        // 核心模块代码、函数、类
    }
}

2. 核心作用

两层命名空间逻辑:外层圈项目/公司,内层圈功能模块

  • 第一层 myproject:相当于品牌/项目名,全局唯一,防止和第三方库命名冲突;
  • 第二层 core:相当于功能分类,专门存放核心逻辑、公共组件、基础模块。

3. 类比其他语言

  • C 语言 :没有 namespace,只能给函数/变量手动加前缀模拟,比如 myproject_core_func()
  • Python :namespace 等价于包/模块/文件夹,通过 import 导入隔离命名;

4. 为什么不推荐只写一层

只写 namespace core,别人的项目也可能定义同名空间,极易命名冲突

两层嵌套 myproject::core 全局唯一,大型项目、开源框架全是这种写法。

5. 大厂开源项目通用写法

Qt、Google Abseil、虚幻引擎,全是外层项目名、内层功能模块的多层 namespace 套路,结构清晰、隔离彻底。


二、C++ 虚函数到底是什么?为什么要设计虚函数?

1. 大白话定义

虚函数:父类定义函数,允许子类重写;用父类指针指向子类对象时,自动调用子类的实现,实现多态。

2. 无虚函数 vs 有虚函数 对比

没有虚函数:父类指针调用父类方法。

有虚函数:父类指针自动调用子类方法。

3. 为什么语言要设计虚函数?

  1. 实现多态:一个统一接口,不同子类有不同实现;
  2. 开闭原则:父类定框架,新增功能只加子类,不用修改旧代码;
  3. 统一管理:可以用父类容器存放所有子类对象,循环统一调用方法;
  4. 消灭臃肿 if-else:不用大量判断类型来调用对应函数。

三、override 关键字:可以不写,但强烈建议写

1. 能不能不写?

能。子类重写虚函数,不写 override 也能正常多态,编译运行都没问题。

2. 为什么推荐必须写

override 不是给程序用的,是给编译器做语法校验

  • 防止函数名手写错;
  • 防止参数列表、返回值和父类对不上;
  • 防止不小心写成新函数,而非重写;

一旦签名不匹配,编译器直接报错,提前规避隐性 Bug,团队开发规范强制要求加。


四、虚函数、纯虚函数、抽象类、抽象函数关系

1. 概念对齐

  • 普通虚函数virtual void func(){},父类有默认实现,子类可重写、也可不重写;
  • 纯虚函数(抽象函数)virtual void func() = 0;,父类不实现,强制子类必须重写
  • 抽象类 :包含至少一个纯虚函数的类,不能 new 实例化,只能作为父类被继承。

2. 核心区别

  1. 普通虚函数类:可以创建对象,子类可选重写;
  2. 抽象类:不能创建对象,子类必须实现所有纯虚函数才能实例化。

3. 和 Java 对应关系

  • C++ 纯虚函数 ⇋ Java 抽象方法;
  • C++ 含纯虚函数的抽象类 ⇋ Java 抽象类;
  • C++ 没有 interface 关键字,用全纯虚函数的类模拟接口

五、C++ 与 Java 编程习惯差异

  1. C++
  • 默认成员函数不是虚函数,必须手动加 virtual
  • 做接口规范:用纯虚函数抽象类
  • 做多态覆写:用普通虚函数
  1. Java
  • 普通方法默认自带动态绑定,天生等价 C++ 虚函数;
  • 做规范、强制实现:直接用 interface 接口 + abstract 抽象类;
  • 架构常用:抽象类做模板、接口做能力定义。

总结一句:C++ 靠纯虚函数模拟接口,Java 原生用 interface 做接口;本质都是父类定规范,子类实现细节


六、protected 权限精讲(public/private/protected 对比)

1. 三大权限大白话

  • public:所有人都能访问(外部、子类、本类);
  • private:只有本类自己能用,子类都无权访问
  • protected:本类能用 + 子类能用 + 外部其他人都不能用

2. 生活化类比

  • public:小区广场,谁都能进;
  • private:个人卧室,只自己用;
  • protected:家庭家产,自己能用、子女能继承,外人无权动用。

七、工程规范:父类虚函数为什么常用 protected?

1. 核心规范

  • 需要对外直接给外部调用 的虚函数:写 public
  • 只给子类重写、不对外暴露 的虚函数:写 protected(项目 80% 都是这种)。

2. 工业级标准模板写法(模板方法模式)

cpp 复制代码
class Base
{
public:
    // 对外公开固定接口
    void exec()
    {
        preWork();
        doExec();
        afterWork();
    }

    // 虚析构,继承必备
    virtual ~Base() = default;

private:
    void preWork()  { }
    void afterWork(){ }

protected:
    // 纯虚函数:留给子类重写
    virtual void doExec() = 0;
};

3. 这种写法的好处

  1. 固定外层业务流程,只把变化点留给子类扩展;
  2. 隐藏内部虚函数,外部不能随意调用,封装性更好;
  3. 遵循设计模式模板方法模式,大厂 C++ 框架标准写法;
  4. 权限隔离清晰:public 对外、protected 给子类、private 内部私有。

八、全文核心总结

  1. 两层 namespace:外层项目隔离,内层功能分类,避免命名冲突;
  2. 虚函数核心:实现多态,父类定框架,子类做扩展,消灭大量 if-else;
  3. override 建议必加:编译期校验函数签名,避免隐性重写失败 Bug;
  4. 纯虚函数=抽象函数,含纯虚函数的类=抽象类,不能实例化,强制子类实现;
  5. C++ 无 interface,用纯虚类模拟接口;Java 原生用 interface,思想完全一致;
  6. protected:本类+子类可用,外部不可用,专门给子类继承复用;
  7. 工程规范:对外接口 public,留给子类重写的虚函数统一放 protected,标准框架写法。

相关推荐
不会编程的懒洋洋1 小时前
C# P/Invoke 基础
开发语言·c++·笔记·安全·机器学习·c#·p/invoke
直奔標竿1 小时前
Java开发者AI转型第二十五课!Spring AI 个人知识库实战(四)——RAG来源追溯落地,拒绝AI幻觉
java·开发语言·人工智能·spring boot·后端·spring
时空系1 小时前
认识Rust——我的第一个程序 Rust中文编程
开发语言·后端·rust
yqcoder1 小时前
JavaScript 柯里化:把“大餐”拆成“小炒”的艺术
开发语言·javascript·ecmascript
每天吃饭的羊2 小时前
JSZip的使用
开发语言·javascript
24白菜头2 小时前
【无标题】
c++·笔记·学习·harmonyos
qq_589568102 小时前
java基础学习,案例练习,即时通讯
java·开发语言·学习
DevilSeagull2 小时前
Windows 批处理 (Batch) 编程: 从入门到入土. (一) 基础概念与环境配置
开发语言·windows·后端·batch·语言