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

VS2019编译C++自定义异常类报C2440无匹配构造函数错误

问题背景

出于兴趣编写代码时,需要实现一个支持格式化输出的自定义异常类,自行编码完成后使用VS2019编译触发错误,相关代码、编译输出、编译参数如下。

项目代码

Error.h

#pragma once
#include <stdarg.h>
#include <cstdio>
#include <iostream>
#include <stdexcept>


namespace DynTyping {
    class Exception : public std::exception {

    protected:
        static const char* Name;
        const char* msg;

        virtual void Initialize(char* format, va_list args);

    public:
        Exception();
        explicit Exception(char* format, va_list args);
        explicit Exception(char* format, ...);
        explicit Exception(const char* format, va_list args);
        explicit Exception(const char* format, ...);
        const char* what();
    };

    class MemoryException : public Exception {
    protected:
        static const char* Name;
    };
}

Error.cpp

#include "Error.h"


namespace DynTyping {

    const char* Exception::Name = "Exception";

    void Exception::Initialize(char* format, va_list args) {
        char msg[256];
        vsprintf_s(msg, format, args);
        char full_msg[256];
        sprintf_s(full_msg, "%s: %s", this->Name, msg);
        this->msg = full_msg;
    }
    Exception::Exception() : std::exception::exception() {
        this->msg = "Exception: an error occurred";
    }

    Exception::Exception(char* format, va_list args) : std::exception::exception() {
        this->Initialize(format, args);
    }
    Exception::Exception(char* format, ...) {
        va_list args;
        va_start(args, format);
        this->Initialize(format, args);
        va_end(args);
    }
    Exception::Exception(const char* format, va_list args) : std::exception::exception() {
        this->Initialize((char*)format, args);
    }
    Exception::Exception(const char* format, ...) : std::exception::exception() {
        va_list args;
        va_start(args, format);
        this->Initialize((char*)format, args);
        va_end(args);
    }
    const char* Exception::what() {
        return this->msg;
    }
    const char* MemoryException::Name = "MemoryException";
}

Test.cpp

#include "Error.h"


int main(int argc, char** argv) {
    using DynTyping::MemoryException;

    throw MemoryException("coucou");
}

编译错误输出

Build started...
1>------ Build started: Project: Test, Configuration: Debug x64 ------
1>Error.cpp
1>Test.cpp
1>C:\Users\XXX\Documents\XXX\Prog\cpp\Test\Test\Test.cpp(7,32): error C2440: '<function-style-cast>': cannot convert from 'const char [7]' to 'DynTyping::MemoryException'
1>C:\Users\XXX\Documents\XXX\Prog\cpp\Test\Test\Test.cpp(7,32): message : No constructor could take the source type, or constructor overload resolution was ambiguous
1>Generating Code...
1>Done building project "Test.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

编译参数

/JMC /permissive- /ifcOutput "x64\Debug\" /GS /W3 /Zc:wchar_t /I"C:\Program Files\Python310\include" /ZI /Gm- /Od /sdl /Fd"x64\Debug\vc143.pdb" /Zc:inline /fp:precise /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /FC /Fa"x64\Debug\" /EHsc /nologo /Fo"x64\Debug\" /Fp"x64\Debug\Test.pch" /diagnostics:column 
错误原因
  • 直接触发编译错误的核心原因:派生类MemoryException未继承基类构造函数。C++语法规则下,派生类不会自动继承基类的构造函数,你在MemoryException里只定义了静态成员Name,没有声明任何构造函数,也没有通过using语句引入基类构造函数,因此执行throw MemoryException("coucou")时,编译器找不到能接收const char*类型参数的MemoryException构造函数,最终报重载解析失败的C2440错误。
  • 代码还存在两个隐藏的运行时问题,即便修复编译错误也会导致异常行为:
    • Initialize函数中将栈上局部字符数组full_msg的地址赋值给成员变量msg,函数退出后栈内存自动回收,msg会成为悬空指针,调用what()时会出现乱码,甚至触发内存访问违规崩溃。
    • 基类中what()方法缺少const修饰,和std::exception基类的虚函数签名不匹配,并没有真正重写基类的虚函数,属于函数隐藏,不符合C++异常类的规范。
修复方案

按以下步骤修改代码即可解决问题:

  1. 在MemoryException类中添加using声明,继承基类Exception的所有构造函数,修改后的MemoryException定义如下:
    class MemoryException : public Exception {
    protected:
        static const char* Name;
    public:
        using Exception::Exception;
    };
    
  2. 修复悬空指针问题:将成员变量msg从const char*类型改为长度256的字符数组成员char msg[256],修改Initialize逻辑,直接把格式化后的错误信息写入成员数组,不要指向栈上临时内存,参考实现如下:
    // 头文件中修改msg和Initialize定义
    protected:
        static const char* Name;
        char msg[256]; // 替换原const char* msg;
        virtual void Initialize(const char* format, va_list args);
    
    // cpp中修改Initialize实现
    void Exception::Initialize(const char* format, va_list args) {
        char tmp[256];
        vsprintf_s(tmp, format, args);
        sprintf_s(this->msg, "%s: %s", this->Name, tmp);
    }
    
    // 同时修改默认构造函数逻辑
    Exception::Exception() : std::exception() {
        strcpy_s(this->msg, "Exception: an error occurred");
    }
    
  3. 修正what()方法签名,添加const和noexcept修饰,加上override关键字确保正确重写基类虚函数:
    const char* what() const noexcept override {
        return this->msg;
    }
    
  4. 优化const正确性:将所有构造函数、Initialize函数中的char* format入参统一改为const char* format,去掉代码中强制把const char*转为char*的不安全写法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 21:42:17