乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • C++ 学习路径
  • 第1章 C++概述与开发环境

    • C++ 语言概述与编译模型
    • 第一个 C++ 程序与规范
    • 开发环境配置
    • 预处理指令详解
  • 第2章 基本语法与类型系统

    • 变量与基本类型
    • 类型转换
    • 枚举类型
    • 引用与指针
    • 数组与 stdarray
    • 字符串与原始字符串字面量
    • const 与 constexpr
    • nullptr 与空指针
    • 类型推导 auto 与 decltype
    • 基于范围的 for 循环
    • 值类别全面解析
    • char16_t 与 char32_t
    • static_assert 编译期断言
  • 第3章 函数与重载

    • 函数声明与定义
    • 函数重载
    • 默认参数与内联函数
    • Lambda 表达式
    • 函数对象与 stdfunction
    • 后置返回类型与 noexcept
  • 第4章 类与对象

    • 类的基本定义
    • 构造函数与析构函数
    • 拷贝控制
    • 移动构造函数与移动赋值
    • 列表初始化与类内初始化器
    • 静态成员与嵌套类
    • 友元
    • =default 与 =delete
  • 第5章 继承与多态

    • 继承基础
    • 虚函数与多态
    • 虚函数表与动态绑定原理
    • 虚析构函数
    • 抽象类与纯虚函数
    • 多重继承与虚继承
    • 继承构造函数
  • 第6章 运算符重载

    • 运算符重载基础
    • 算术与关系运算符重载
    • 赋值与移动运算符重载
    • 特殊运算符重载
  • 第7章 模板与泛型编程

    • 函数模板
    • 类模板
    • 模板特化与偏特化
    • 可变参数模板
    • 别名模板与模板模板参数
    • SFINAE 与类型萃取
    • 依赖名与 typename/template 关键字
  • 第8章 异常处理

    • 异常处理机制
    • noexcept 与异常安全
    • RAII 与异常安全实践
  • 第9章 内存管理与智能指针

    • 动态内存与内存分区
    • RAII 惯用法
    • unique_ptr
    • shared_ptr 与 weak_ptr
    • 内存管理最佳实践
  • 第10章 右值引用与移动语义

    • 右值引用与值类别深度解析
    • std::move 原理与使用
    • 完美转发与 std::forward
    • 移动语义性能对比与最佳实践
  • 第11章 STL容器

    • vector 深度剖析
    • deque 内部机制
    • list 与 forward_list
    • map 与 set 深度解析
    • unordered 容器与哈希原理
    • array 与 tuple
    • 容器适配器
    • 容器选择全景指南
  • 第12章 STL算法与迭代器

    • 迭代器体系全解
    • 非变异算法
    • 变异算法
    • 排序与二分算法
    • Lambda 与算法组合
    • std::random 随机数库
    • 自定义迭代器开发
  • 第13章 IO流与文件

    • 标准 IO 流
    • 格式化输出控制
    • 文件流操作
    • 字符串流
    • std::regex 正则表达式
  • 第14章 并发与多线程

    • thread 基础与线程管理
    • mutex 与 lock_guard
    • unique_lock 与 condition_variable
    • thread_local 线程局部存储
    • atomic 与内存序
    • future 与 async 异步编程
    • std::chrono 时间库
  • 第15章 现代C++新特性

    • 从 C++11 到 C++20 演进路线
    • C++14 关键新特性
    • C++17 关键新特性
    • C++20 核心特性速览
  • 第16章 面试考点与最佳实践

    • C++ 综合最佳实践清单
    • 高频面试题精讲
    • 多线程面试题与实战
    • 内存管理常见陷阱与排查
  • 附录

    • C++ 核心知识点
    • C++ 专业术语

继承构造函数

定义与作用

继承构造函数是 C++11 引入的语法,通过 using Base::Base 将基类的所有非特殊构造函数一次性引入派生类,消除派生类中"为每个基类构造函数写一个透传构造函数"的重复样板代码。

class Base {
public:
    Base(int);
    Base(const std::string&);
    Base(int, double);
};

class Derived : public Base {
public:
    using Base::Base;  // 继承 Base 的全部构造函数
    // 效果等同于为 Base 的每个构造函数写了透传版本
};
场景C++03 写法C++11 写法
基类有 3 个构造函数派生类写 3 个透传构造函数using Base::Base 一行

核心原理

继承语义

继承规则详解

不继承默认/拷贝/移动构造函数的理由:如果自动继承这些特殊成员,会导致派生类的特殊成员行为与预期严重不符——派生类通常需要自己的拷贝/移动逻辑(处理派生类自己的成员)。

完整示例

示例一:飞翔科技通知系统的继承构造

场景说明:孔蓝设计了一套通知消息体系,基类 Notification 有多个构造函数,子类通过继承构造函数简化代码。

#include <iostream>
#include <string>
#include <memory>
#include <vector>

// 基类:通知消息
class Notification {
public:
    Notification() : title_("系统通知"), priority_(0) {
        std::cout << "  [默认构造] " << title_ << std::endl;
    }

    Notification(std::string title, int priority)
        : title_(std::move(title)), priority_(priority) {
        std::cout << "  [主构造] " << title_
                  << " (优先级: " << priority_ << ")" << std::endl;
    }

    explicit Notification(std::string title)
        : Notification(std::move(title), 1) {}  // 委托构造

    virtual ~Notification() = default;

    virtual void display() const {
        std::cout << "[" << priority_ << "] " << title_ << std::endl;
    }

protected:
    std::string title_;
    int priority_;
};

// 派生类:系统警告 —— 继承基类全部构造函数
class SystemAlert : public Notification {
public:
    using Notification::Notification;  // C++11 继承构造函数

    void display() const override {
        std::cout << "⚠️ 系统警告: " << title_
                  << " (级别 " << priority_ << ")" << std::endl;
    }
};

// 派生类:用户消息 —— 同样继承
class UserMessage : public Notification {
public:
    using Notification::Notification;

    void display() const override {
        std::cout << "📩 用户消息: " << title_
                  << " (优先级 " << priority_ << ")" << std::endl;
    }
};

int main() {
    std::cout << "===== 飞翔科技通知中心 =====" << std::endl;

    std::cout << "\n-- 创建 SystemAlert 对象 --" << std::endl;
    SystemAlert alert1("数据库连接超时", 5);
    SystemAlert alert2("磁盘空间不足");     // 单参数:委托到主构造
    SystemAlert alert3;                      // 默认构造

    std::cout << "\n-- 创建 UserMessage 对象 --" << std::endl;
    UserMessage msg1("孔蓝提交了需求文档", 2);
    UserMessage msg2("版本发布通知");

    std::cout << "\n-- 通知列表 --" << std::endl;
    alert1.display();
    alert2.display();
    alert3.display();
    msg1.display();
    msg2.display();

    return 0;
}

预期输出:

===== 飞翔科技通知中心 =====

-- 创建 SystemAlert 对象 --
  [主构造] 数据库连接超时 (优先级: 5)
  [主构造] 磁盘空间不足 (优先级: 1)
  [默认构造] 系统通知

-- 创建 UserMessage 对象 --
  [主构造] 孔蓝提交了需求文档 (优先级: 2)
  [主构造] 版本发布通知 (优先级: 1)

-- 通知列表 --
⚠️ 系统警告: 数据库连接超时 (级别 5)
⚠️ 系统警告: 磁盘空间不足 (级别 1)
⚠️ 系统警告: 系统通知 (级别 0)
📩 用户消息: 孔蓝提交了需求文档 (优先级 2)
📩 用户消息: 版本发布通知 (优先级 1)

逐段分析:

  • using Notification::Notification 一行语句,让 SystemAlert 和 UserMessage 继承了基类的所有非特殊构造函数
  • alert1("数据库连接超时", 5) 调用的是继承来的双参数构造函数
  • alert2("磁盘空间不足") 调用的是基类 explicit Notification(string) 委托构造函数,该函数又委托给主构造函数——继承构造函数正确保留了委托链
  • 继承的构造函数会完美转发参数给基类,就像为每个基类构造函数手写了 Derived(args) : Base(std::forward<Args>(args)...) {}
  • 派生类自己的成员在继承构造函数中会被默认初始化——如果需要自定义初始化派生类成员,继承构造函数不够用

示例二:多重继承中的构造函数冲突

场景说明:白歌设计一个同时继承两个工具类的子类,处理构造函数签名冲突。

#include <iostream>
#include <string>

// 基类 A:记录创建日志
class Logger {
public:
    Logger(const std::string& category) : category_(category) {
        std::cout << "[Logger] 创建日志分类: " << category_ << std::endl;
    }

    Logger(int verbosity) : verbosity_(verbosity) {
        std::cout << "[Logger] 详细级别: " << verbosity_ << std::endl;
    }

    const std::string& category() const { return category_; }
    int verbosity() const { return verbosity_; }

private:
    std::string category_ = "default";
    int verbosity_ = 0;
};

// 基类 B:记录时间戳
class Timestamp {
public:
    Timestamp(const std::string& format) : format_(format) {
        std::cout << "[Timestamp] 时间格式: " << format_ << std::endl;
    }

    Timestamp(int precision) : precision_(precision) {
        std::cout << "[Timestamp] 精度: " << precision_ << " 位" << std::endl;
    }

    const std::string& format() const { return format_; }
    int precision() const { return precision_; }

private:
    std::string format_ = "ISO";
    int precision_ = 3;
};

// 多重继承:两个基类都有 string 和 int 构造函数——签名冲突
class AuditLog : public Logger, public Timestamp {
public:
    // 签名冲突:Logger(string) 和 Timestamp(string) 都是 string 参数
    // 签名冲突:Logger(int) 和 Timestamp(int) 都是 int 参数
    // 无法直接 using Logger::Logger; using Timestamp::Timestamp;

    // 解决方案:手动消歧
    using Logger::Logger;
    using Timestamp::Timestamp;

    // 当两个基类都有相同签名的构造函数时,该签名的继承会被"禁用"
    // 必须手动实现:
    AuditLog(const std::string& category)
        : Logger(category), Timestamp("ISO") {}  // 手动消歧

    AuditLog(int level)
        : Logger(level), Timestamp(level) {}      // 手动消歧

    void report() const {
        std::cout << "[AuditLog] " << category()
                  << " | " << format()
                  << " | 详细度 " << verbosity() << std::endl;
    }
};

int main() {
    std::cout << "===== 飞翔科技审计日志 =====" << std::endl;

    std::cout << "\n-- 冲突签名:string --" << std::endl;
    AuditLog log1("系统操作");

    std::cout << "\n-- 冲突签名:int --" << std::endl;
    AuditLog log2(5);

    std::cout << "\n-- 审计报告 --" << std::endl;
    log1.report();
    log2.report();

    return 0;
}

预期输出:

===== 飞翔科技审计日志 =====

-- 冲突签名:string --
[Logger] 创建日志分类: 系统操作
[Timestamp] 时间格式: ISO

-- 冲突签名:int --
[Logger] 详细级别: 5
[Timestamp] 精度: 5 位

-- 审计报告 --
[AuditLog] 系统操作 | ISO | 详细度 0
[AuditLog] default | ISO | 详细度 5

逐段分析:

  • 当两个直接基类都声明了相同签名的构造函数时,using 声明会产生冲突——该签名的继承构造函数被隐式删除
  • 开发者必须手动为冲突签名提供构造函数,显式决定如何给两个基类传递参数
  • 本示例中 AuditLog(string) 和 AuditLog(int) 都是手动消歧的结果——分别指定给哪个基类传什么值
  • 非冲突签名(如果存在)仍然可以通过 using 自动继承
  • 这与普通的成员 using 声明冲突规则一致:引入多个同名实体时,如果产生歧义则必须手动消歧

易错场景与面试考点

易错场景

场景错误表现正确做法
认为继承构造函数包含默认/拷贝/移动派生类缺少这些特殊成员特殊成员不会被继承,需要时自行定义
多重继承中签名冲突未手动消歧该签名的继承构造函数被隐式删除手动实现构造函数并显式初始化两个基类
继承构造函数中派生类成员未初始化派生类成员为不确定值使用类内初始化器(int x = 0;)或手动实现构造函数
混淆继承构造函数与委托构造函数认为是同类构造函数间委托继承构造函数转发给基类,委托构造函数转发给同类另一个构造
私有/保护基类构造函数被继承后访问级别以为自动变为 public继承构造函数保持基类中的访问级别

常见面试问题

  1. 继承构造函数的原理是什么?——using Base::Base 为基类的每个非特殊构造函数在派生类中生成一个签名相同的构造函数,函数体仅完美转发参数给基类构造。效果等同于为每个基类构造函数手写 Derived(args) : Base(forward<Args>(args)...) {}。

  2. 哪些构造函数不会被继承?——默认构造函数、拷贝构造函数、移动构造函数。这些属于"特殊成员函数",有独立于普通构造函数的生成规则。

  3. 继承构造函数与委托构造函数的区别?——继承构造函数(using Base::Base)将构造转发给基类;委托构造函数(Derived() : Derived(args))将构造转发给同类的另一个构造函数。方向完全不同。

  4. 多重继承中继承构造函数冲突如何处理?——当两个基类有签名相同的构造函数时,using 声明会冲突,该签名需要手动消歧:在派生类中显式定义该构造函数,明确给两个基类分别传什么参数。

  5. 派生类成员在继承构造函数中如何初始化?——继承构造函数对派生类成员执行默认初始化。如果需要自定义初始化,应使用类内初始化器(C++11 非静态成员初始化器,如 int x_ = 0;)或放弃继承构造函数改为手动实现。

小结

  • using Base::Base 将基类非特殊构造函数引入派生类,消除透传样板代码
  • 不会继承默认/拷贝/移动构造函数——这些特殊成员有独立的生成规则
  • 继承的构造函数保持基类中的访问级别(public/protected)
  • 多重继承签名冲突需要手动消歧
  • 派生类成员在继承构造函数中获得默认初始化——需要特殊初始化时用类内初始化器或手写构造函数
  • 与委托构造函数区分:继承 → 基类,委托 → 同类另一个构造
上一页
多重继承与虚继承