Почему этот код компилируется и правильно печатает "Derived"
?
template <class Derived>
class Base
{
public:
Base(Derived& d) : derived(d) {}
void f() { std::cout << "Base\n"; }
virtual ~Base() { derived.f(); }
private:
Derived& derived;
};
class Derived : public Base<Derived>
{
public:
Derived() : Base<Derived>(*this) {}
void f() { std::cout << "Derived\n"; }
};
int main()
{
Derived d;
}
Но либо создание Base::f
virtual
либо как Derived::f
и Base::f
виртуальных вызывает "Base"
для печати. Кроме того, изменение Derived::f
на virtual
дает Invalid memory reference (SIGSEGV)
. Я ожидаю, что эти два других случая напечатают "Derived", так как я называю это из экземпляра Derived
.
Почему это происходит?
Это болтливая ссылка.
Вы инициализируете поле Base::derived
как ссылку на объект Derived
через конструктор Derived
, но затем вы получаете доступ к нему в деструкторе Base
после уничтожения объекта Derived
.
Доступ к любому объекту после его уничтожения (с помощью указателя или ссылки) является неопределенным поведением, поэтому может случиться что угодно.