指向派生 class 的指针的重载解析

Overload resolution for pointer to derived class

accept 一个指向基的指针 class 然后根据它的派生类型调用不同的函数。

[编辑

问题是:accept 是管理器 class 的 public 方法,它处理和存储大量 A、B1、B2(shared_ptr 个)实例。 Manager会根据运行时的实际类型来处理它们

编辑]

#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

我是不是对继承有误解?

没有virtual调度,重载解析在编译时执行,即基于对象的静态类型,而不是动态类型。由于 ab2std::shared_ptr<A>,因此选择了 A 重载。

要涉及运行-时间类型信息(即对象的动态类型),必须使用virtual方法(和多态),而不是重载解析。目前尚不清楚如何最好地将其合并到给定的示例中。

最直接的方法是给 A 一个虚析构函数和一些虚方法,如 accept(),在派生 类 中被重写,以分派到最合适的自由函数重载明确地。还有其他方法,这取决于您的需要。

还应注意,此代码中没有任何 SFINAE。


重申并回应编辑:如果你想使用动态而不是静态类型信息,你的类型必须至少有一个虚拟方法:

class A { virtual ~A(); };

如果你这样做,那么你可以使用例如dynamic_cast(或者,因为你正在使用 std::shared_ptrstd::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,那么您可能没有正确的抽象。查看变体或访问者模式(或在新问题中寻求此建议,在其中详细说明问题和限制)。