Виртуальная функция требуется для обеспечения надлежащего удаления совместно используемого объекта. В отличие от unique_ptr
, shared_ptr
не требует полного знания этого типа при его создании. Например. Вы можете сделать это:
class Foo;
std::shared_ptr<Foo> foo = make_foo();
Обратите внимание, что в коде выше мы не имеем полного типа Foo, только опережающее объявление. Если мы допустим, что foo
выходит из области видимости, объект, на который он указывает, будет корректно удален, потому что когда Foo
был создан в make_foo
, был создан делетер, который знает полный тип Foo
и, следовательно, может вызвать соответствующие деструкторы. (Например Возможно make_foo
создает Bar
, который наследует от Foo
и возвращает его. shared_ptr
«s будет обрабатывать этот штраф.)
функция на объекте DeleteR, что shared_ptr
создает для управления делеция Foo
будет виртуальным, что позволяет shared_ptr
к вызовите правильный деструктор.
Грубо это может быть что-то вроде этого:
struct deleter_interface {
virtual void ~deleter_interface = default;
virtual void dispose() = 0;
};
template <typename T>
struct deleter : deleter_interface {
T* ptr_;
deleter(T* ptr) : ptr_(ptr) {}
virtual void dispose() { delete ptr_; }
};
template <typename T>
shared_ptr {
T* ptr_;
deleter_interface* deleter_;
...
};
template <typename T>
shared_ptr<T>::shared_ptr<T>(T* ptr)
: ptr_(ptr), deleter_(new deleter<T>(ptr)) {}
template <typename T>
shared_ptr<T>::~shared_ptr<T>() { deleter_->dispose(); delete deleter_; }
Хотя это кажется более сложным, строго необходимым, чтобы позволить shared_ptr
использоваться без полного типа. Например, что если вы хотите сделать это:
В ах:
struct Foo;
std::shared_ptr<Foo> a = make_object();
// ... let a go out of scope
И в a.cc:
struct Foo { ... };
struct Bar : Foo { ... };
std::shared_ptr<Foo> make_object() { return std::shared_ptr<Foo>(new Bar); }
Если мы не имеем виртуальную функцию, используемую в Deleter кода, то Bar
не будет разрушен правильно. С виртуальной функцией не имеет значения, что заголовок (a.h) никогда не видит определения Foo
или Bar
.
Или он дал имя «виртуальной функции» механизму «стирания типа»? – GamovCoder
[Тип удаления удаления] (http://stackoverflow.com/q/5450159/2756719) требует использования виртуальных функций. (Ну, технически он этого не требует, но это самый удобный способ его реализации.) –