指向派生 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
调度,重载解析在编译时执行,即基于对象的静态类型,而不是动态类型。由于 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
,那么您可能没有正确的抽象。查看变体或访问者模式(或在新问题中寻求此建议,在其中详细说明问题和限制)。
我 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
调度,重载解析在编译时执行,即基于对象的静态类型,而不是动态类型。由于 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
,那么您可能没有正确的抽象。查看变体或访问者模式(或在新问题中寻求此建议,在其中详细说明问题和限制)。