You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++基类引用指向派生类为何调用基类虚函数?异常切片疑问

C++ 问题解答

问题1:为何指向派生类对象的基类类型引用会调用基类的虚函数?

正常情况下,基类引用指向派生类对象时,调用虚函数应该触发派生类的覆盖版本。如果实际调用了基类的虚函数,通常是以下原因之一:

  • 基类函数未声明为virtual:如果基类的函数没有virtual修饰,调用会采用静态绑定,编译器根据引用的静态类型(基类)直接调用基类函数,无视实际指向的派生类对象。
  • 派生类未正确覆盖虚函数:派生类的函数签名必须和基类虚函数完全一致(返回值支持协变、参数列表、const/volatile限定符等都要匹配),否则派生类的函数是全新的独立函数,不构成覆盖。比如基类函数是virtual void func() const,派生类写成void func(),就不会覆盖基类的虚函数。
  • 覆盖失败未被发现:如果没有使用override关键字强制检查覆盖,签名不匹配的错误可能被隐藏,导致程序依然调用基类函数。

问题2:异常抛出中throw e与throw *p的类型表现差异

代码片段

// exception constructor
#include <iostream>  // std::cout
#include <exception> // std::exception
#include <cxxabi.h>

#define PRINT_TYPENAME(f) std::cout << abi::__cxa_demangle(typeid(f).name(), 0, 0, &status) << std::endl;

struct ooops : std::exception
{
    const char *what() const noexcept { return "Ooops!\n"; }
};

int main()
{
    ooops e;
    std::exception *p = &e;

    // demangle the typeid
    char *realname;
    int status;
    PRINT_TYPENAME(p);
    PRINT_TYPENAME(*p);

    try
    {
        throw e; // throwing copy-constructs: ooops(e)
    }
    catch (std::exception &ex)
    {
        std::cout << ex.what();
    }
    try
    {
        throw *p; // throwing copy-constructs: std::exception(*p)
    }
    catch (std::exception &ex)
    {
        std::cout << ex.what();
    }
    return 0;
}

输出

std::exception*
ooops
Ooops!
std::exception

差异原因分析

  1. typeid(*p)输出ooops的原因:
    std::exception是含有虚函数的多态类,typeid作用于多态类的左值表达式时,会动态识别对象的实际类型,所以*p虽然静态类型是std::exception,但实际指向ooops对象,因此typeid(*p)返回ooops的类型信息。

  2. throw e与throw *p的差异:
    C++中抛出异常时,会根据表达式的静态类型创建异常对象,这会触发对象切片:

  • throw e:e的静态类型和动态类型都是ooops,因此创建的异常对象是ooops类型。catch块中用std::exception&捕获时,由于多态特性,调用的是ooops重写的what(),输出Ooops!。
  • throw *p:*p的静态类型是std::exception,即使它实际指向ooops对象,编译器也会按std::exception类型复制对象,切片掉派生类ooops的部分,最终异常对象是std::exception类型。此时catch块调用的是基类的what(),输出std::exception。

内容的提问来源于stack exchange,提问作者pikalee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 06:44:56