基于unique_ptr参数指针类型的重载函数

m.t*_*cey 4 c++ overloading hierarchy unique-ptr

我的印象是unique_ptr可以以与普通指针相同的方式推断类层次结构,但是当我尝试重载这样的函数时:

void func(unique_ptr<Derived1>& d1);
void func(unique_ptr<Derived2>& d2);
Run Code Online (Sandbox Code Playgroud)

然后调用这样的函数之一:

unique_ptr<Base> b = make_unique<Derived1>();
func(b);    
Run Code Online (Sandbox Code Playgroud)

我收到一个错误说no instance of overloaded function "func" matches the argument list。b 的运行时类型是Derived1,所以我预计会调用第一个重载。

此外,当我unique_ptr从函数返回 a 时,编译器能够将派生类(?不确定合适的术语)转换为基类,以便像这样工作:

unique_ptr<Base> create(){
    return make_unique<Derived1>();
}
Run Code Online (Sandbox Code Playgroud)

通常在我的代码中,我将变量声明为这样的函数的结果。它们被声明为基类,但具有派生的运行时类型,我想将它们传递给一个重载函数。

我如何以与使用涉及类层次结构的常规指针相同的方式重载函数?

lub*_*bgr 6

您是对的,所有标准智能指针的隐式转换操作都为原始指针建模。这允许编译第二个片段,即

unique_ptr<Base> create(){
    return make_unique<Derived1>();
}
Run Code Online (Sandbox Code Playgroud)

然而,关于第一个片段有一个误解,因为从来没有一个从基类到派生类的内置隐式向下转换。使用普通指针,

void func(Derived1* d1);
void func(Derived2* d2);

Base* b =  new Derived1();
func(b);
Run Code Online (Sandbox Code Playgroud)

也不会编译。这在基本的 OOP 意义上是有意义的 - 通过基类接口查看继承层次结构中的对象,并隐藏实际的具体运行时类型。

如果您需要具有这种调度的设计,您需要阅读“访问者”设计模式,它实现了一种称为双重(或多重)调度的技术。但是实现这一点所需的样板数量给了你一个提示,为什么该语言不提供这种作为内置的调度。

  • 尝试做出决定:如果您不断需要向下转型,那么虚拟多态性可能不是您问题的错误设计。然后,您可以使用不隐藏具体实例的总和类型,如 @Jarod42 建议的那样。否则,找出一些基类接口适用于大多数用例的方法(并且客户端不需要具体的子类类型信息来完成他们的工作)。 (2认同)