自定义异常中的用户定义的空构造函数,具有多个继承和抽象基类



我设计了几个自定义异常,由于多重继承,它们都继承自同一个抽象基类custom::exception和相应的标准异常。 因此,我的自定义异常中有一个特定的层次结构,我可以一般或具体地捕获它们。

现在我打开了所有警告,GCC 没有任何问题,但 clang 抱怨虚拟析构函数:

#include <iostream>
#include <stdexcept>
namespace custom {
struct exception;
struct buffer_overflow;
struct null_pointer;
struct out_of_range;
//...
}
struct custom::exception {
virtual ~exception() noexcept {}
virtual const char* what() const noexcept = 0;
};
struct custom::null_pointer : public custom::exception, public std::logic_error {
null_pointer(const std::string &str): std::logic_error(str) {}
const char* what() const noexcept override { return std::logic_error::what(); }
};
int main(){
try{
throw custom::null_pointer("[ERROR] NULL pointer exception !");
}
catch(const custom::exception &error){
std::cout << error.what() << std::endl;
}
}

使用 g++ 输出(MinGW.org GCC-8.2.0-3(

[ERROR] NULL pointer exception !

使用 clang++版本 6.0.0-1ubuntu2输出:

test.cpp:13:13: warning: definition of implicit copy constructor for 'exception' is deprecated because it has a
user-declared destructor [-Wdeprecated]
virtual ~exception() noexcept {}
^
test.cpp:17:16: note: in implicit copy constructor for 'custom::exception' first required here
struct custom::null_pointer : public custom::exception, public std::logic_error {
^
test.cpp:24:15: note: in implicit move constructor for 'custom::null_pointer' first required here
throw custom::null_pointer("[ERROR] NULL pointer exception !");
^
1 warning generated.
[ERROR] NULL pointer exception !

我不太明白,因为custom::exception是抽象的,不包含任何成员变量,所以它不需要用户定义的构造函数。但是,如果我定义这些,clang不会抱怨:

struct custom::exception {
exception() noexcept {}
exception(const exception&) noexcept {}
virtual ~exception() noexcept {}
virtual const char* what() const noexcept = 0;
};

我的问题是:

  1. 哪个编译器是正确的?
  2. 为什么我必须定义空的默认值和复制构造函数,如上面?

谢谢。

相关问题 :

  • C++ 抽象类:构造函数是还是否?
  • 定义抽象基类的默认构造函数

您遇到了同样的问题 警告:隐式复制构造函数的定义已弃用 遇到过:

在C++标准D.2 Implicit declaration of copy functions [depr.impldec]中,C++17 N4659草案指出:

默认复制构造函数的隐式定义是 如果类具有用户声明的复制赋值运算符,则不推荐使用 或用户声明的析构函数。副本的隐式定义 如果类具有 用户声明的复制构造函数或用户声明的析构函数 (15.4, 15.8(. 在本标准的未来修订版中,这些隐含的定义可能会被删除(11.4(。

这给出了答案

1.:两个编译器都是正确的,clang实际上警告你弃用,gcc没有,这也是可以的。

这没关系,因为 D(0( 将有关它的警告设为可选,甚至是[[deprecated]]属性,该属性也不是发出警告的强制性要求:

实现可以声明 中描述的库名称和实体 此部分具有已弃用的属性

阿拉伯数字。为了迫使你思考所谓的三法则:三法则指出,由于你需要定义一个构造函数,你可能需要一个复杂的复制和/或移动构造函数。通过强迫你显式定义它们,即使有default,它作为一种保险,类作者已经考虑了切片和其他问题。但是,由于隐式或默认的复制构造函数只是复制您的基和元素,因此您应该没问题。

你可以默认,它基本上与隐式定义的东西相同,但你想要一个虚拟析构函数,否则是相同的:

exception() noexcept = default;
exception(const exception&) noexcept = default;
virtual ~exception() noexcept = default;

最新更新