2012-04-21 150 views
8

如果這個答案已經被我回頭看了,並且找不到答案,我會提前道歉。智能指針和dynamic_cast

注意:這IS一個家庭作業的任務,所以如果你覺得不舒服回答,我完全理解。

我有以下幾點:

ptr.h:

template<typename T> 
class Ptr { 
    T* address; 
    size_t* counter; 
    Ptr(T* address) : address(address), counter(new size_t(1)) { } 
    Ptr(const Ptr& other) : address(other.address), counter(other.counter) 
    { 
     ++(*counter); 
    } 
    virtual ~Ptr() { 
     if (0 == --(*counter)) { delete address; delete counter; } 
    } 
    Ptr& operator=(const Ptr& right) { 
     if (address != right.address) { 
      if (0 == --(*counter)) { delete address; delete counter; } 
      address = right.address; 
      counter = right.counter; 
      ++(*counter); 
     } 
     return *this; 
    } 
    T& operator*() const { TRACE(address); return *address; } 
    T* operator->() const { TRACE(address); return address; } 
    T* raw()  const { TRACE(addr); return addr; } 
}; 

main.cc:現在

#include <iostream> 
#include "ptr.h" 

using std::cout; 
using std::endl; 


class Base { 
public: 
    Base() { std::cout << "Base()" << std::endl; } 
    virtual ~Base() { std::cout << "~Base()" << std::endl; } 
    virtual std::string str() { return "In Base::str()"; } 
}; 

class Derived: public Base { 
public: 
    Derived() { std::cout << "Derived()" << std::endl; } 
    ~Derived() { std::cout << "~Derived()" << std::endl; } 
    std::string str() { return "In Derived::str()"; } 
}; 



int main() { 
Ptr<Base> base(new Base()); 
Ptr<Derived> derived(new Derived()); 

Ptr<Base> pbase(0); 
Ptr<Derived> pderived(0); 

    // upcasting can be done like this, but is it the best way? 
    pbase = *((Ptr<Base>*)(&derived)); 
    cout << pbase->str() << endl; // outputs: "In Derived::str()" 

    /* 
    * downcasting should be done using dynamic_casts 
    * but how can I downcast here? 
    * what do I know so far: 
    * 1. just because Derived is a subclass of Base does not mean Ptr<Derived> is a 
    * subclass of Ptr<Base> so there is no hierarchy between the two so I cannot 
    * really use dynamic_casts here 
    * 2. The dynamic_cast I do use is sort of useless no? since pbase is a Ptr<Base> 
    */ 
    pderived = *((Ptr<Derived>*)(dynamic_cast<Ptr<Base>*>(&pbase))); 
    cout << pderived->str() << endl; 


return 0; 
} 

,我們的目標是使用dynamic_cast的去來回,和雖然我發現很多關於智能指針的有趣花絮沒有真正解釋這是如何實現的。

我試圖剛開地址字段PBASE,然後初始化pderived到一個新的PTR與地址,但當然,我的引用計數得到了所有搞砸了。

我試圖創建一個新的PTR那舉行的pderived計數器的參考,但隨後我無法設置的pderived所以我被困有太多的地址字段。

我告訴你們這個信息,因爲:1。 我想提出一個觀點,我一直在做這個很長一段時間,詢問在線幫助和 2之前,我想讓你知道我是什麼已經嘗試過了。

我真的可以在這裏使用一些建議。只是如何得到:

pderived = <SOMETHINGSOMETHING>pbase<SOMETHINGSOMETHING> 

謝謝!

+3

如果它功課不要擔心。只要確保你把家庭作業標籤。人們只會尋找能夠引導你朝着正確方向而不是直接給出答案的答案。 – chris 2012-04-21 23:23:03

+0

這是一個很好的閱讀,如果你想更全面的解釋:http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions – chris 2012-04-21 23:37:41

+0

感謝您的鏈接:)我wasn不知道作業標籤 – mlnyc 2012-04-22 14:48:43

回答

6

典型地,智能指針類會暴露一個動態鑄造包裝,與下面的智能指針對象正確的交易。例如,C++ 0x具有dynamic_pointer_cast函數。請注意,您的*((Ptr<Derived>*)(dynamic_cast<Ptr<Base>*>(&pbase)));可能並將會中斷,特別是如果您有多重繼承,因爲它不會將address的內部指針調整到子類中的右側偏移量以獲取所需的任何超類。

在實現級別,一個引用計數智能指針類通常會攜帶在每個智能指針兩個指針;直接一個點的對象(正確地澆鑄到任何類型的指針是),以及一個點到包含一個引用計數,一個指針到原始對象,和指向例程缺失的結構。這允許指針的任何鑄造變體正確取回原始對象並調用其析構函數。目前,您直接指向size_t,這不會提供此信息。在任何情況下,一旦你對析構函數有這樣的間接性,當它投出這些智能指針的時候,那麼,你只能指向外部的指針;只有當銷燬時間流逝時纔會留下內部參考計數結構。

其實轉向到所有這些代碼,當然,就留給讀者做練習:)

+0

「和指向刪除例程的指針」 - 或直接刪除函數對象。 – Xeo 2012-04-21 23:46:40

+0

是的,那是另一種選擇。或者,您可以擁有帶有純虛擬刪除例程的基本refcount結構,以及實現刪除例程的模板子類以及它可能需要的任何狀態。等等。 – bdonlan 2012-04-21 23:55:31

+1

這實際上就是我所知道的所有實現。 [STL關於'shared_ptr'如何在2012年GoingNative會議上發表了精彩的演講](http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/STL11-Magic-Secrets)。 – Xeo 2012-04-22 02:19:51