Есть ли способ определить тип объекта?

Это может быть глупый вопрос, я подозреваю, что знаю ответ (нет), потому что я, кажется, здесь бью стену.

Учитывая, что у меня есть коллекция объектов, полученных из определенного класса:

class BaseClass;
class DerivedA: public BaseClass;
class DerivedB: public BaseClass;
class DerivedC: public BaseClass;
std::vector<BaseClass> myCollection;

Я хочу вызвать метод в зависимости от типов конкретного класса:

class Processor {
void doSomething(DerivedA a, DerivedB b);
void doSomething(DerivedA a, DerivedC c);
}

Проблема в том, что если я получу доступ к отдельным элементам в коллекции и попытаюсь вызвать метод doSomething в «Процессоре», он не сможет решить, какой метод использовать (afaik). Итак, мой вопрос: есть ли способ получить элементы в коллекции с правильным производным типом?

0

Решение

Если вы собираетесь сохранить doSomething метод, как он есть, это то, что называется многократная отправка и в настоящее время НЕ поддерживается C ++.

Если бы это была функция виртуального члена BaseClass тогда да, это будет запуск полиморфизма мельницы C ++ на объекте, к которому он вызывается, но он все равно НЕ будет автоматически определять тип аргумента.

Чтобы обойти это, вы можете сделать что-то вроде того, что предлагается в предыдущей ссылке

void collideWith(Thing& other) {
// dynamic_cast to a pointer type returns NULL if the cast fails
// (dynamic_cast to a reference type would throw an exception on failure)
if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) {
// handle Asteroid-Asteroid collision
} else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) {
// handle Asteroid-Spaceship collision
} else {
// default collision handling here
}
}

По сути, продолжайте приведение к различным возможным классам Derived, пока один из них не сработает и не вызовет один из методов соответствующим образом (без особых усилий, так как компилятор знает, к какому типу вы пытаетесь привести).

ВАЖНО: как указывает @WhozCraig, ваш вектор должен содержать указатели, чтобы избежать Объектно-нарезка и сделать весь этот вопрос спорным.

2

Другие решения

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

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

class DerivedA;
class DerivedB;
class DerivedC;

class BaseClass
{
public:
virtual ~BaseClass();

virtual void doSomethingWithBase( BaseClass & b2 ) = 0;
virtual void doSomethingWithDerivedA( DerivedA & da ) = 0;
virtual void doSomethingWithDerivedB( DerivedB & db ) = 0;
virtual void doSomethingWithDerivedC( DerivedC & dc ) = 0;
};

class DerivedA : public BaseClass
{
public:

void doSomethingWithBase( BaseClass & b2 )
{
b2.doSomethingWithDerivedA( *this );
}

void doSomethingWithDerivedA( DerivedA & da )
{
// implement for two DerivedA objects
}

void doSomethingWithDerivedB( DerivedB & db )
{
// implement for an A and B
}

void doSomethingWithDerivedC( DerivedC & dc )
{
// implement for an A and C
}
};

// implement DerivedB to call doSomethingWithDerivedB on its parameter
// implement DerivedC to call doSomethingWithDerivedC on its parameter.

Вы поняли идею. Оттуда, где вы звоните, вам не нужно знать, какие у вас есть два типа, и вам никогда не нужно искать это. Но если вы когда-нибудь добавите больше реализаций, у вас будет много кода для редактирования, и вы можете рассмотреть какую-то таблицу поиска.

Если вам нужен класс для определения самого себя, вы можете использовать какой-то виртуальный идентификатор.

  class BaseClass
{
public:
virtual int id() const = 0;
};

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

1

По вопросам рекламы [email protected]