为什么 gcc/clang 抱怨基 class 有一个受保护的析构函数,而不抱怨派生的 class?
Why do gcc/clang complain about the base class having a protected destructor, but not about the derived class?
以下代码使用 Visual Studio 2019 编译,但不使用 gcc 和 clang。定义变量 b
会导致后两个编译器出错。
#include <iostream>
class base
{
public:
constexpr base(int i) : m_i(i) {}
constexpr int i() const { return m_i; }
protected:
~base() = default; // Forbid polymorphic deletion
private:
const int m_i;
};
class derived final : public base
{
public:
constexpr derived() : base(42) {}
};
// Defining b compiles with Visual Studio 2019,
// but does not with gcc and clang.
// gcc 11.2: error: 'base::~base()' is protected within this context
// clang 13.0: error: variable of type 'const base' has protected destructor
constexpr base b(41);
// Defining d compiles with all 3 compilers.
constexpr derived d;
int main()
{
std::cout << b.i() << std::endl;
std::cout << d.i() << std::endl;
}
哪些编译器是正确的?编译程序的是微软,还是不编译程序的gcc和clang?
如果 gcc 和 clang 是正确的,为什么错误出现在 b 而不是 d?
更新:
FWIW,如果我如下更改 base
,Visual Studio 2019 也不会编译程序:
class base
{
public:
constexpr base(int i) : m_i(i) {}
constexpr int i() const { return m_i; }
protected:
//~base() = default; // Forbid polymorphic deletion
// This does not compile with Visual Studio 2019 either.
~base() {}
private:
const int m_i;
};
但据我所知,默认析构函数和手动实现的析构函数之间应该没有区别,所以是的,我猜这是 MS 编译器中的一个错误。
析构函数是一个成员函数,因此不能在无法调用其他成员函数的上下文中调用它。
调用的上下文是对象构造的上下文(见下文),因此在您的情况下,您不能在 base
之外调用 ~base()
(或从 [= 派生的 class 11=]),这就是为什么 gcc 和 clang(它们是正确的)出现错误的原因。
[class.dtor#15] [...] In each case, the context of the invocation is the context of the construction of the object. [...]
错误出现在 b
而不是 d
,因为 derived
的隐式声明的析构函数是 public:
[class.dtor#2] If a class has no user-declared prospective destructor, a prospective destructor is implicitly declared as defaulted ([dcl.fct.def]).
An implicitly-declared prospective destructor is an inline public member of its class.
使 base
的析构函数默认为 protected 或 private 不会使子 classes 的析构函数默认为 protected 或 private,您只需获得隐式定义的析构函数,即 public.
以下代码使用 Visual Studio 2019 编译,但不使用 gcc 和 clang。定义变量 b
会导致后两个编译器出错。
#include <iostream>
class base
{
public:
constexpr base(int i) : m_i(i) {}
constexpr int i() const { return m_i; }
protected:
~base() = default; // Forbid polymorphic deletion
private:
const int m_i;
};
class derived final : public base
{
public:
constexpr derived() : base(42) {}
};
// Defining b compiles with Visual Studio 2019,
// but does not with gcc and clang.
// gcc 11.2: error: 'base::~base()' is protected within this context
// clang 13.0: error: variable of type 'const base' has protected destructor
constexpr base b(41);
// Defining d compiles with all 3 compilers.
constexpr derived d;
int main()
{
std::cout << b.i() << std::endl;
std::cout << d.i() << std::endl;
}
哪些编译器是正确的?编译程序的是微软,还是不编译程序的gcc和clang?
如果 gcc 和 clang 是正确的,为什么错误出现在 b 而不是 d?
更新:
FWIW,如果我如下更改 base
,Visual Studio 2019 也不会编译程序:
class base
{
public:
constexpr base(int i) : m_i(i) {}
constexpr int i() const { return m_i; }
protected:
//~base() = default; // Forbid polymorphic deletion
// This does not compile with Visual Studio 2019 either.
~base() {}
private:
const int m_i;
};
但据我所知,默认析构函数和手动实现的析构函数之间应该没有区别,所以是的,我猜这是 MS 编译器中的一个错误。
析构函数是一个成员函数,因此不能在无法调用其他成员函数的上下文中调用它。
调用的上下文是对象构造的上下文(见下文),因此在您的情况下,您不能在 base
之外调用 ~base()
(或从 [= 派生的 class 11=]),这就是为什么 gcc 和 clang(它们是正确的)出现错误的原因。
[class.dtor#15] [...] In each case, the context of the invocation is the context of the construction of the object. [...]
错误出现在 b
而不是 d
,因为 derived
的隐式声明的析构函数是 public:
[class.dtor#2] If a class has no user-declared prospective destructor, a prospective destructor is implicitly declared as defaulted ([dcl.fct.def]). An implicitly-declared prospective destructor is an inline public member of its class.
使 base
的析构函数默认为 protected 或 private 不会使子 classes 的析构函数默认为 protected 或 private,您只需获得隐式定义的析构函数,即 public.