2016-12-01 29 views
0

我正在閱讀Scott Meyers的智能指針上的項目28 更有效的C++並存在以下問題。在隱式轉換的智能指針上刪除函數調用中的歧義

完整的演示可在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

沒有回答qustion,但'返回的SmartPtr (足尖e);'看起來不正確,你需要像'std :: week_ptr'這樣的東西 –

+0

你應該看看標準的智能指針,以及它們如何將轉換(例如)從'std :: shared_ptr '轉換爲'std :: shared_ptr '當(並且僅當)'Derived *'可以轉換爲'Base *'時。 –

+0

您的演員表是正確的,缺少的是你的拷貝構造函數的代碼。如果你有一個需要非const的參考 - 你會得到你提到的錯誤,如果你只需要將ref修改爲在ct中的const並且代碼將被編譯(測試) –

回答

0
//constructors 

這是你省略了:)

你投是這樣正確的最重要的部分,這一切都取決於你設置有構造函數。如果你有一個非const的引用 - 你會得到你提到的錯誤,如果你可以將ref修改爲在ct中的const並且代碼將被編譯。

可能不是很明顯,但是當你調用

return SmartPtr<NewType>(pointee); 

你正在構建新的SmartPtr<NewType>有接受T*,並NewTypeT是不同的類型。很可能你只有ctor接受相同類型的原始指針(即T*SmartPtr<T>和爲SmartPtr<X>),所以編譯器是尋找另一個converting ctor以創建新的SmartPtr,發現您的拷貝構造函數,但它不能將新值綁定到非const的參考


編輯:

如果您正在使用C++ 11加入移動男星也將解決你的問題,因爲它是能夠綁定到右值

SmartPtr(SmartPtr<T>&& other): pointee(other.pointee) { other.pointee = nullptr; } 
+0

感謝Oleg的幫助。您可以在我在http://ideone.com/aKq6C0上面提供的ideone頁面中查看'SmartPtr'的完整定義。我直接從這本書中獲得了它,並且'SmartPtr'的行爲基本上決定它必須在它的拷貝構造函數中使用一個非const引用(類似於不推薦的'auto_ptr')。 –

+0

你使用的是C++ 11嗎?你也可以通過添加移動ctor來解決你的問題? 'SmartPtr(SmartPtr &&)'.. –

相關問題