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

Overload resolution for pointer to derived class

本文关键字:重载 指针 派生      更新时间:2023-10-16

我会accept指向基类的指针,然后根据其派生类型调用不同的函数。

[ 编辑

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

编辑 ]

#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不同类型的类型,那么您可能没有正确的抽象。查看变体或访问者模式(或在一个新问题中询问此建议,详细说明您的问题和约束(。