【发布时间】:2017-04-16 06:45:14
【问题描述】:
我正在阅读 Scott Meyers 的 More Effective C++ 的智能指针的第 28 项,并且有以下问题。
完整的演示可以在http://ideone.com/aKq6C0 找到。
派生类指针可以隐式转换为基类指针:
class Base {};
class Derived : public Base {};
void foo(Base* b) { cout << "foo called on Base pointer" << endl;}
Derived *d = new Derived();
foo(d); //No problem
但是这种隐式转换不能发生在智能指针上,即SmartPtr<Derived>不能隐式转换为SmartPtr<Base>。所以我们使用成员模板进行此类转换:
template<typename T>
class SmartPtr {
public:
//constructors, operator->, etc
//member template for type conversion
template<NewType>
operator SmartPtr<NewType> () {
return SmartPtr<NewType>(pointee);
}
private:
T* pointee;//the raw pointer
};
这几乎可以工作,但它可能会导致歧义:
class Remote {};
class Base : public Remote {};
class Derived : public Base {};
void foo(const SmartPtr<Remote>& p) { cout << "remote" << endl;}
void foo(const SmartPtr<Base>& p) { cout << "base" << endl;}
SmartPtr<Derived> d(new Derived());
foo(d);//compile error: ambiguity
在此示例中,编译器不知道是否应将d 转换为SmartPtr<Base> 或SmartPtr<Remote>,尽管对于原始指针Base 显然更胜一筹。书上说
我们能做的最好的事情是使用成员模板来生成转换函数,然后在产生歧义的情况下使用强制转换。
但是我们究竟如何在这里应用演员表? foo(static_cast<SmartPtr<Base>>(d)) 也不编译。从错误消息中我可以看出错误来自SmartPtr 的复制构造函数中使用非常量引用。我想知道进行函数调用的正确方法是什么。
【问题讨论】:
-
不回答问题,但
return SmartPtr<NewType>(pointee);似乎不对,你需要std::week_ptr之类的东西才能做到这一点 -
您应该查看标准智能指针,以及当(且仅当)
Derived*可转换为Base*时,它们如何提供从std::shared_ptr<Derived>到std::shared_ptr<Base>的转换(例如)。 -
您的演员表是正确的,缺少的是您的复制构造函数的代码。如果您有一个采用非常量 ref - 您会收到您提到的错误,如果您可以在复制 ctor 中将 ref 更改为 const 并且代码将编译(测试)
标签: c++ smart-pointers implicit-conversion ambiguous