The following code compiles with Visual Studio 2019, but not with gcc and clang. Defining the variable b
causes an error with the latter two compilers.
#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;
}
Which of the compilers are right? Microsoft, which compiles the program, or gcc and clang, which do not?
And if gcc and clang are right, why does the error show up for b, but not for d?
CodePudding user response:
A destructor is a member-function, so it cannot be called in context where you would not be able to call other member functions.
The context of the call is the context of the construction of the object (see below), so in your case you cannot call ~base()
outside of base
(or a class derived from base
), which is why you get the error with gcc and clang (which are correct).
[class.dtor#15] [...] In each case, the context of the invocation is the context of the construction of the object. [...]
The error shows up for b
and not for d
because the implicitly declared destructor of derived
is 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.
Making the destructor of base
protected or private does not make the destructor of child classes protected or private by default, you simply get the implicitly defined destructor, which is public.