我正在阅读关于Scott Meyers的更有效的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
的拷贝构造函数中使用非const引用。我想知道调用函数的正确方法是什么。
答案 0 :(得分:0)
//constructors
这是你省略的最重要的部分:)
你的演员阵容是正确的,这完全取决于你拥有的一组构造函数。如果你有一个非const引用 - 你会得到你提到的错误,如果你可以将ref更改为复制ctor中的const并且代码将编译。
可能不是很明显,但是当你打电话时
return SmartPtr<NewType>(pointee);
您正在构建必须接受SmartPtr<NewType>
的新T*
,而NewType
和T
是不同的类型。很可能你只有ctor接受相同类型的原始指针(例如T*
为SmartPtr<T>
而X*
为SmartPtr<X>
)因此编译器正在寻找另一个SmartPtr( SmartPtr<T>&& other): pointee(other.pointee) { other.pointee = nullptr; }
创建新的SmartPtr并找到你的副本ctor,但它不能将新值绑定到非const ref
编辑:
如果您正在使用c ++ 11添加移动ctor也可以解决您的问题,因为它可以绑定到右值
{{1}}