Разрешение перегрузки для указателя на производный класс - PullRequest
0 голосов
/ 14 октября 2019

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

[EDIT

Проблема в том, что: accept является открытым методомКласс менеджера, который обрабатывает и хранит множество экземпляров A, B1, B2 (shared_ptr of). Диспетчер будет иметь дело с ними, основываясь на фактическом типе времени выполнения

EDIT]

#include <memory>
#include <iostream>

class A {};
class B1 : public A {};
class B2 : public A {};

void accept(std::shared_ptr<B1> sp)  { std::cout << "B1 "; }

// How to ensure the overload call to right derived type ?
void accept(std::shared_ptr<A> sp)   {
  std::cout << "A ";
  // if runtime type of sp.get is B1, do something
  // elif is B2, something else...
  // then if is A, do another thing
}

void accept(std::shared_ptr<B2> sp)  { std::cout << "B2 "; }

int main(int argc, char**argv)
{
    auto a = std::make_shared<A>();
    auto b1 = std::make_shared<B1>();
    auto b2 = std::make_shared<B2>();
    std::shared_ptr<A> ab2 = std::make_shared<B2>(): // !!!

    accept(a);
    accept(b1);
    accept(b2);
    accept(ab2);                                     // !!!
}

Выходные данные A B1 B2 A. Я хочу B2 для последнего.

Я неправильно понимаю наследование?

1 Ответ

4 голосов
/ 14 октября 2019

Без диспетчеризации virtual перегруженное разрешение выполняется во время компиляции, то есть на основе статического типа объектов, а не динамического типа . Поскольку ab2 является std::shared_ptr<A>, выбирается перегрузка A.

Чтобы задействовать информацию типа времени выполнения (т. Е. Динамический тип объекта), необходимо использовать методы virtual (иполиморфизм), а не разрешение перегрузки. Не ясно, как лучше всего включить это в данный пример.

Самый простой способ - предоставить A виртуальный деструктор и некоторый виртуальный метод, такой как accept(), который переопределяется в производных классах для отправки большинствусоответствующая перегрузка свободной функции явно. Однако есть и другие способы, это зависит от того, что вам нужно.

Следует также отметить, что в этом коде вообще нет SFINAE.


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

class A { virtual ~A(); };

Если вы это сделаете, то можете использовать, например, dynamic_cast (или,поскольку вы используете std::shared_ptr, std::dynamic_pointer_cast) для определения типа объекта во время выполнения:

void accept(std::shared_ptr<B1> sp)  { std::cout << "B1 "; }

void accept(std::shared_ptr<B2> sp)  { std::cout << "B2 "; }

// How to ensure the overload call to right derived type ?
void accept(std::shared_ptr<A> sp) {
  if (std::shared_ptr<B1> ptrB1 = std::dynamic_pointer_cast<B1>(sp))
    accept(ptrB1);
  else if (std::shared_ptr<B2> ptrB2 = std::dynamic_pointer_cast<B2>(sp))
    accept(ptrB2);
  else
    // if is A, do another thing
}

Но если вы вручную dynamic_cast между различными типами, как этоттогда у вас, вероятно, нет нужной абстракции. Посмотрите на варианты или шаблон посетителя (или спросите этот совет в новом вопросе, в котором вы подробно опишите проблему и имеющиеся у вас ограничения).

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