C++ 从std::exception派生的类的赋值运算符

C++ 从std::exception派生的类的赋值运算符,c++,inheritance,assignment-operator,C++,Inheritance,Assignment Operator,我从std::runtime\u error 静态分析器警告我,如果我定义或删除默认操作(复制构造函数、复制/移动操作符、析构函数等),我应该定义或删除它们 为了解决这个愚蠢的警告,我编写了缺少的赋值运算符,但随后我得到另一个警告,现在我的运算符隐藏了基本的非虚拟赋值运算符 由于基类有我无法复制的私有成员,所以看起来唯一的解决方案是直接为基类对象部分调用基类asignment操作符,然后复制其余的*this对象,最后返回*this 但在此之前,我看了一下基本操作符=的功能,这里是它的外观: ex

我从
std::runtime\u error

静态分析器警告我,如果我定义或删除默认操作(复制构造函数、复制/移动操作符、析构函数等),我应该定义或删除它们

为了解决这个愚蠢的警告,我编写了缺少的赋值运算符,但随后我得到另一个警告,现在我的运算符隐藏了基本的非虚拟赋值运算符

由于基类有我无法复制的私有成员,所以看起来唯一的解决方案是直接为基类对象部分调用基类asignment操作符,然后复制其余的
*this
对象,最后返回
*this

但在此之前,我看了一下基本
操作符=
的功能,这里是它的外观:

exception& operator=(exception const& _Other) noexcept
{
    if (this == &_Other)
    {
        return *this;
    }

    __std_exception_destroy(&_Data);
    __std_exception_copy(&_Other._Data, &_Data);
    return *this;
}
private:

    __std_exception_data _Data;
};
现在知道这是我的实现(带注释)来调用base asignment并复制派生对象的其余部分:

class Exception :
    public std::runtime_error
{
public:

    // ...

    Exception& operator=(const Exception& other)
    {
        if (this == &other)
        {
            return *this;
        }

        // first copy only base class data to *this
        *dynamic_cast<std::runtime_error*>(this) =
            runtime_error::operator=(
                *dynamic_cast<std::runtime_error*>(
                    const_cast<Exception*>(&other)));

        // then copy derived class data to *this
        mInfo = other.mInfo;
        mCode = other.mCode;

        // finally return complete copy
        return *this;
    }

private:
    std::error_code mCode;
    std::string mInfo;
};
类异常:
公共std::运行时错误
{
公众:
// ...
异常和运算符=(常量异常和其他)
{
如果(此==&其他)
{
归还*这个;
}
//首先,仅将基类数据复制到*此
*动态_cast(本)=
运行时错误::运算符=(
*动态浇铸(
const_cast(及其他));
//然后将派生类数据复制到*this
mInfo=other.mInfo;
mCode=other.mCode;
//最后返回完整副本
归还*这个;
}
私人:
std::错误代码mCode;
std::字符串mInfo;
};
这样做正确吗?我想这看起来有点麻烦,但我不确定

编辑

以下是完整的课程,供参考:

#pragma warning (disable : 4275)    // base needs to have DLL interface
    class ERROR_API Exception :
        public std::runtime_error
    {
    public:
        ~Exception() noexcept;  // cant be inlined in release build

        // default/delete
        Exception(const Exception&) = default;
        Exception(Exception&&) = delete;

        Exception& operator=(const Exception& other)
        {
            if (this == &other)
            {
                return *this;
            }

            // copy base class data to *this
            *dynamic_cast<std::runtime_error*>(this) =
                runtime_error::operator=(
                    *dynamic_cast<std::runtime_error*>(
                        const_cast<Exception*>(&other)));

            // copy derived class data to *this
            mInfo = other.mInfo;
            mCode = other.mCode;

            return *this;
        }

        Exception& operator=(Exception&&) = delete;

        /** Construct from error enum */
        template<typename Enum>
        Exception(Enum err_enum);

        /** Construct from error enum and string*/
        template<typename Enum>
        Exception(Enum err_enum, String message);

        /** Construct from error_code object */
        inline Exception(std::error_code err_code);

        /** Construct from error_code object and string */
        inline Exception(std::error_code err_code, String message);

        /** Get error_condidtion name */
        inline virtual std::string ConditionName() const;

        /** Get error_category name */
        inline virtual std::string CategoryName() const;

        /** Get error_condition value */
        inline virtual int ConditionValue() const noexcept;

        /** Get error_condition value */
        inline virtual int ErrorValue() const noexcept;

        /** Get additional information string passed to constructor */
        inline virtual const String& GetInfo() const noexcept;

        /** Get error_code object associated with this exception object */
        inline virtual const std::error_code& code() const noexcept;

    private:
        SUPPRESS(4251);     // member needs to have DLL interface
        std::error_code mCode;
        SUPPRESS(4251);     // member needs to have DLL interface
        String mInfo;
    };
#pragma warning (default : 4275)    // base needs to have DLL interface
#pragma warning(disable:4275)//base需要有DLL接口
类错误\u API异常:
公共std::运行时错误
{
公众:
~Exception()noexcept;//不能在发布版本中内联
//默认/删除
异常(常量异常&)=默认值;
异常(异常&&)=删除;
异常和运算符=(常量异常和其他)
{
如果(此==&其他)
{
归还*这个;
}
//将基类数据复制到*此
*动态_cast(本)=
运行时错误::运算符=(
*动态浇铸(
const_cast(及其他));
//将派生类数据复制到*此
mInfo=other.mInfo;
mCode=other.mCode;
归还*这个;
}
异常和运算符=(异常和运算符)=删除;
/**从错误枚举构造*/
模板
异常(枚举错误\枚举);
/**从错误枚举和字符串构造*/
模板
异常(枚举错误、字符串消息);
/**从错误代码对象构造*/
内联异常(标准::错误代码错误代码);
/**从错误代码对象和字符串构造*/
内联异常(std::error\u code err\u code,字符串消息);
/**获取错误条件名称*/
内联虚拟std::string ConditionName()常量;
/**获取类别名称时出错*/
内联虚拟std::string CategoryName()常量;
/**获取错误\u条件值*/
内联虚拟int ConditionValue()常量noexcept;
/**获取错误\u条件值*/
内联虚拟int ErrorValue()常量noexcept;
/**获取传递给构造函数的附加信息字符串*/
内联虚拟常量字符串&GetInfo()常量noexcept;
/**获取与此异常对象关联的错误代码对象*/
内联虚拟常量std::error_code&code()常量noexcept;
私人:
SUPPRESS(4251);//成员需要有DLL接口
std::错误代码mCode;
SUPPRESS(4251);//成员需要有DLL接口
弦敏福;
};
#pragma warning(默认值:4275)//base需要有DLL接口

多亏了乌尔里希·埃克哈特、彼得和其他人的精彩评论,以下是我如何让它工作的,结果根本没有任何警告:

class Exception : public std::runtime_error
{
public:
    ~Exception() noexcept;  // can't be inlined in release build (defaulted in source)

    // default/delete
    Exception(const Exception&) noexcept = default;
    Exception(Exception&&) noexcept = default;
    Exception& operator=(const Exception&) noexcept = default;
    Exception& operator=(Exception&&) noexcept(false) = deault;

    // the rest of the code ...
};

那么,为什么您需要实现或删除任何特殊成员?这看起来像是一个很好的零类规则。在你开始添加东西之前,请发布原始类,只是一些基本内容,也许它还可以,而你的静态分析器(哪个?)过于激进。首先,静态分析器为你提供了两种可能的解决方法。我想你选错了,删除这些是我的选择。这就是说,所有这些动态抛出的东西都是不必要的,只要记住
operator=
也可以作为方法调用,所以您只需调用
runtime\u error::operator=(other)
就可以分派到基类。如果您打算实现其他默认操作,那么让编译器定义它们,直到您准备好定义自己的操作为止。最多将它们定义为一个存根,以后可以完成。无论如何,隐藏警告可能是因为您的
运算符=()
与继承的运算符不一致
std::exception
s
operator=()
具有
throw()
规范(C++11之前)或
noexcept
(C++11及更高版本)。您的派生类需要与之一致-否则您的
操作符=()
会根据标准隐藏基类版本。鉴于静态分析器不同于编译器及其库(定义
std::exception
和派生类的地方),对此你可能无能为力。只需记录静态分析仪发出警告的事实,以及您已确定其可接受的事实(即假阳性)。如果静态分析器支持此类功能,请向
异常
类添加注释,以防止静态分析器对此发出警告。你需要阅读文档