Использование класса Derived с помощью std:: shared_ptr базового класса

Хороший ли следующий подход?

class TA { };
class TB : TA { };
std::shared_ptr<ta> spta;
spta.reset(new TB);
</ta>
3 ответа

Там одна проблема с показанным кодом, TB должна наследоваться публично из TA. У вас есть shared_ptr, поэтому указатель, который вы хотите сохранить в нем, должен быть конвертирован в TA, но с наследованием private база недоступна, поэтому ваш код не будет компилироваться.

class TA { };
class TB : public TA { };

Помимо этого, код не имеет ошибок и хорошо себя ведет. Обычно, когда вы выполняете полиморфное удаление экземпляра производного класса с помощью указателя базового класса, вам нужно, чтобы деструктор базового класса был virtual, поэтому вызывается деструктор производного класса, но в случае shared_ptr это необязательно. shared_ptr::reset - это шаблон функции, который примет любой Y*, который можно конвертировать в тип управляемого указателя. То же самое верно для shared_ptr шаблон конструктора.

При этом вам следует предпочесть сделать деструктор базового класса virtual, особенно если задействованные классы имеют другие функции virtual.


Нет, это не для TA является закрытым.

Кроме того, как было предложено в комментариях, деструктор базового класса должен быть виртуальным. Обычно это хорошая практика, поскольку вы не можете гарантировать, что экземпляры ваших классов будут использоваться только с общими указателями.

Чтобы он работал, вы должны хотя бы изменить следующие строки:

class TA { };
class TB : TA { };

Как следует:

class TA { virtual ~TA() { } };
class TB : public TA { };

Те, которые хороши, поскольку следующий пример хорош:

class TA { virtual ~TA() { } };
class TB : public TA { };
TA *spta = nullptr;
spta = new TB;

В основном это зависит от того, какие хорошие средства для вас. Это законно, по крайней мере.


Это не ответ на вопрос, это попытка устранить любую путаницу в том, что shared_ptr, казалось бы, магическая способность избегать использования виртуального деструктора.

Вот небольшая демонстрационная программа:

#include <iostream>
#include <memory>
struct A { ~A() { std::cout << __func__ << std::endl; } void foo() { do_foo(); }
protected: virtual void do_foo() { std::cout << "A::" << __func__ << std::endl; }
};
struct B : A { ~B() { std::cout << __func__ << std::endl; } virtual void do_foo() override { std::cout << "B::" << __func__ << " "; A::do_foo(); }
};
using namespace std;
auto main() -> int
{ std::shared_ptr<a> p = std::make_shared</a><a>(); p->foo(); p = std::make_unique<b>(); p->foo(); cout << "deleting B:" << endl; return 0;
}
</b></a></memory></iostream>

ожидаемый вывод:

A::do_foo
~A
B::do_foo A::do_foo
deleting B:
~B
~A

Обратите внимание, что правильный деструктор вызывается, когда B был уничтожен в конце main().

licensed under cc by-sa 3.0 with attribution.