我正在阅读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引用。我想知道做函数调用的正确方法是什么。
//constructors
这是您省略的最重要部分:)
您的演员表是正确的,这一切都取决于您拥有的一组构造函数。如果您有一个非const Ref的人 - 您会收到提到的错误,如果您只能将Ref更改为复制ctor中的const,并且代码将编译。
可能不是很明显,但是当您致电
时return SmartPtr<NewType>(pointee);
您正在构建必须接受T*
的新SmartPtr<NewType>
,而NewType
和T
是不同的类型。您很可能只有CTOR接受相同类型的原始指针(即SmartPtr<T>
的T*
,X*
和SmartPtr<X>
),因此编译器正在寻找另一个转换CTOR来创建您的新smartptr并找到您的副本CTOR,但无法绑定新值,但它无法绑定新值到非const ref
编辑:
如果您使用的是C 11添加移动CTOR也可以解决您的问题,因为它可以绑定到RVALUE
SmartPtr( SmartPtr<T>&& other): pointee(other.pointee) { other.pointee = nullptr; }