Нет, это невозможно.
Функция, которая вызывается, выбирается по адресу время компиляции. Допустим, у вас есть такой код:
Base &o = getSomeObject();
handle(o);
Компилятор не знает тип O реального. Он знает только, что это какой-то подтип Base
или Base
. Это означает, что он будет искать функцию, которая захватывает объекты типа Base
.
Вы могли бы реализовать проверку типа самостоятельно или использовать карту для хранения возможных функций:
Base &o = getSomeObject();
functionMap[typeid(o)](o);
Но typeid
работает только этот whay если Base
является полиморфным типом. Это означает, что у него должна быть хотя бы одна виртуальная функция . Это приводит нас к следующему разделу:
Но вы можете использовать виртуальные функции.
Virtual functionsнестатические функции-члены классов, которые могут быть переопределены. Правильная функция разрешена во время выполнения. Следующий код будет выходной Subt
вместо Base
:
class Base {
public: virtual std::string f() {return "Base"}
};
class Subt : public Base {
public: virtual std::string f() {return "Subt"}
};
int main() {
Subt s;
Base &b = s;
std::cout << b.f() << std::endl;
}
Вы можете опустить virtual
в определении Subt
. Функция f()
уже определена как virtual в базовом классе.
Классы с по меньшей мере одной виртуальной функции (также называемые полиморфные типы) хранят ссылку на таблицу в виртуальной функции (также называемые виртуальные таблицы). Эта таблица используется для получения правильной функции во время выполнения.
Проблема в вашем вопросе может быть решена так:
class Parent {
public:
virtual void handle() = 0;
};
class A : public Parent {
public:
void handle() override { /* do something for instances of A */ }
};
class B : public Parent {
public:
void handle() override { /* do something for instances of B */ }
};
class C : public Parent {
public:
void handle() override { /* do something for instances of C */ }
};
int main()
{
std::vector<std::unique_ptr<Parent>> children = {
std::make_unique<A>(),
std::make_unique<B>(),
std::make_unique<C>()};
for (const auto &child : children)
child->handle();
}
Примечание о совместимости: Ключевые слова auto
и override
доступны только в C++ 11 и выше. range-based for loop и std::unique_ptr
также доступны с C++ 11. Функция std::make_unique
доступна с C++ 14. Но виртуальная функция также может использоваться со старыми версиями.
Другой намек:
полиморфизм работает только со ссылками и указателями. Следующий бы назвал Base::f()
и не Subt::f()
:
Subt s;
Base b = s;
std::cout << b.f() << std::endl;
В этом примере b
будет содержать только объект типа Base
вместо Subt
. Объект создается только по адресу Base b = s;
. Он может скопировать некоторую информацию от s
, но это не s
. Это новый объект типа Base
.
прочитайте о полиморфизме и разрезе объектов. – NathanOliver
** Сначала: ** Я думаю, что Parent test2 = A() 'не делает то, что вы думаете. В * C++ * существует полиморфизм только для указателей и ссылок. 'test2' имеет тип' Parent' и построен из 'A', но он больше не имеет типа' A'. ** Второе: ** Перегруженные функции выбираются из компилятора. Если вы хотите вызвать нужную функцию, вам нужно вручную проверить, какой тип она есть. Но вы можете заинтересоваться [* виртуальными функциями *] (http://stackoverflow.com/q/2391679/4967497). С помощью виртуальной функции вы можете сделать 'handle' членом' A', 'B' и' C', и он всегда будет вызывать правильную функцию автоматически. – JojOatXGME
@JojOatXGME Мне известно о возможности проверки вручную типа (с использованием интеллектуального указателя), но у меня было впечатление, что это анти-шаблон. Это верно? –