Проверка подкласса объекта базового класса - наследование - PullRequest
0 голосов
/ 03 июня 2018

Мне нужно знать во время выполнения подтип объекта базового класса, с которым я работаю.

Прежде всего, у меня есть базовый класс с именем Element.Затем у меня есть несколько подклассов с именами Car, Adult ... все они получены из Element.В некоторой части моего кода я создаю несколько объектов этого типа, которые я храню в массиве Element.

Проблема возникает, когда я пробираюсь через массив и пытаюсь восстановить первичный тип объекта.

Я пытался сделать это, используя dynamic_cast, но каждый Element может быть успешно приведен к Car, Adult или как угодно ...

Это код:

Element elements[3];
Car c;
Adult a1;
Adult a2;
elements[0] = c;
elements[1] = a1;
elements[2] = a2;
int numElements = 3;
for(int i = 0; i< numElements; i++){
    if(dynamic_cast<Adult*>(&elements[i]) == nullptr){
        cout << "Its an adult" << endl;
    }else{
        cout << "Sth else" << endl;
    }
}

И вот результат:

Its an adult
Its an adult
Its an adult

Это код подкласса:

class Car : public Element{
    ...
};

class Adult : public Element{
    ...
};

1 Ответ

0 голосов
/ 03 июня 2018

Есть две проблемы с вашим кодом.

One , Element elements[3]; создает массив из Element объектов.Не из "объектов классов, производных от Element".Вы не можете хранить ничего, кроме Element в таком массиве, и любая попытка сделать это приводит к разрезанию объекта : часть, отличная от Element исходного объекта, удаляется (отбрасывается) итолько часть Element делает это.

Если вы хотите динамический полиморфизм, вы должны использовать указатели или ссылки, и обычно также динамическое выделение.В вашем случае это может выглядеть примерно так:

std::unique_ptr<Element> elements[3];
Car c;
Adult a1;
Adult a2;
elements[0] = std::make_unique<Car>(c);
elements[1] = std::make_unique<Adult>(a1);
elements[2] = std::make_uniuqe<Adult>(a2);

Или, если вы хотите избежать копирования объектов:

std::unique_ptr<Element> elements[3];
auto c = std::make_unique<Car>();
auto a1 = std::make_unique<Adult>();
auto a2 = std::make_unique<Adult>();
elements[0] = std::move(c);
elements[1] = std::move(a1);
elements[2] = std::move(a2);

Или просто создать их непосредственно в массиве:

std::unique_ptr<Element> elements[3];
elements[0] = std::make_unique<Car>();
elements[1] = std::make_unique<Adult>();
elements[2] = std::make_unique<Adult>();

Два , вы неправильно интерпретируете результат dynamic_cast.Если dynamic_cast завершается успешно, он возвращает приведение указателя к соответствующему типу.Если это не удается, он возвращает нулевой указатель.Ваше состояние полностью изменено, поскольку вы интерпретируете == nullptr как успех.Цикл должен фактически выглядеть следующим образом (с unique_ptr s из точки # 1 на месте):

for(int i = 0; i< numElements; i++){
    if(dynamic_cast<Adult*>(elements[i].get())){
        cout << "Its an adult" << endl;
    }else{
        cout << "Sth else" << endl;
    }
}

Несколько примечаний:

  • Поскольку ваш Element используется как полиморфный базовый класс, он должен иметь виртуальный деструктор.В противном случае использование указателя типа Element для удаления динамически размещенного объекта типа, производного от Element, приведет к неопределенному поведению (наиболее вероятному повреждению памяти).

  • Если вашElement предназначено только как абстрактная база, и вы никогда не ожидаете, что объекты типа Element (не производные от него) существуют, вы должны сделать Element абстрактным, предоставив ему хотя бы одну чисто виртуальную функцию (virtual void foo() = 0;)).Если это настоящий базовый класс, он, вероятно, будет содержать несколько кандидатов для этого.

  • Необходимость знать точный производный тип при работе с базовым классом часто является признаком плохого дизайна.,В идеале Element должен содержать виртуальные функции, охватывающие все функции, которые вам могут понадобиться для объектов с абстракцией типа.Конечно, существуют исключения, но вам, вероятно, следует пересмотреть свой дизайн, чтобы убедиться, что эти dynamic_casts действительно необходимы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...