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
soperator=()
具有throw()
规范(C++11之前)或noexcept
(C++11及更高版本)。您的派生类需要与之一致-否则您的操作符=()
会根据标准隐藏基类版本。鉴于静态分析器不同于编译器及其库(定义std::exception
和派生类的地方),对此你可能无能为力。只需记录静态分析仪发出警告的事实,以及您已确定其可接受的事实(即假阳性)。如果静态分析器支持此类功能,请向异常
类添加注释,以防止静态分析器对此发出警告。你需要阅读文档