Рассмотрим следующий контур:
class Base { /* ... */ };
class Derived : public Base
{
public:
void AdditionalFunctionality(int i){ /* ... */ }
};
typedef std::shared_ptr<Base> pBase;
typedef std::shared_ptr<Derived> pDerived;
int main(void)
{
std::vector<pBase> v;
v.push_back(pBase(new Derived()));
pDerived p1( std::dynamic_pointer_cast<Derived>(v[0]) ); /* Copy */
pDerived p2 = std::dynamic_pointer_cast<Derived>(v[0]); /* Assignment */
p1->AdditionalFunctionality(1);
p2->AdditionalFunctionality(2);
/* A */
return 0;
}
Здесь я расширяю базовый класс с производным классом, который добавляет функциональность (метод AdditionalFunctionality
).
Первый вопрос, это нормально? Я прочитал много вопросов, которые говорят, что это не нормально, и вы должны объявить дополнительные функциональные возможности базового класса (часто предлагаемые как создание их чистых виртуальных методов в базовом классе). Однако я не хочу этого делать. Я хочу расширить функциональность базового класса, а не просто реализовать его по-разному. Есть ли лучшее решение для достижения этой цели?
Хорошо, поэтому в этом коде я также использую контейнер STL для хранения этих указателей, который позволяет мне хранить указатели на оба объекта типа Base, а также объекты типа Derived без нарезки объектов.
Второй вопрос, это имеет смысл, не так ли? Я, по сути, избегаю резки с помощью указателей на объекты базового класса, а не на объекты базового класса?
Если я "знаю", что определенный указатель относится к производному объекту, я затем использую std::dynamic_pointer_cast
для использования умного указателя.
Третий вопрос, это компилируется без предупреждения и работает, но безопасно ли это? Действительно? Изменит ли он ссылочный аспект общих указателей и не сможет delete
мои объекты или delete
их до того, как я ожидаю?
Наконец, я могу сделать это, используя либо конструктор копирования, либо через назначение, как показано для p1 и p2. Есть ли предпочтительный/правильный способ сделать это?
Похожие вопросы:
- Downcasting shared_ptr <Base> to shared_ptr <Derived> ?: Это очень близко, однако удеренный класс не добавляет дополнительных функций, подобных моим, поэтому я не уверен, что он полностью совпадает. Кроме того, он использует
boost::shared_ptr
, где я используюstd::shared_ptr
(хотя я понимаю, что boost пожертвовал shared_ptr в std-библиотеку, поэтому они, вероятно, совпадают).
Благодарим вас за помощь.
Edit:
Одна из причин, по которой я спрашиваю, заключается в том, что я понимаю, что можно сделать следующее (неправильно):
/* Intentional Error */
v.push_back(pBase(new Base()));
pDerived p3( std::dynamic_pointer_cast<Derived>(v[1]) );
p3->AdditionalFunctionality(3); /* Note 1 */
Где я пытаюсь сжать указатель на объект Base на указатель объекта Derived и затем вызвать метод, который реализуется только в классе Derived. Другими словами, объект, на который указывает, не определяет (или даже не "знает" метод).
Это не улавливается компилятором, но может вызвать segfault в зависимости от того, как определяется AdditionalFunctionality
.