智能指针和dynamic_cast

mln*_*nyc 9 c++ polymorphism dynamic-cast smart-pointers

如果在我看来已经回答这个问题并且找不到答案,我会提前道歉.

注意:这一个家庭作业,所以如果你觉得不舒服,我完全理解.

我有以下内容:

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;  }
};
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

现在,我的目标是使用dynamic_cast来回,虽然我发现许多关于智能指针的有趣花絮但没有真正解释这是如何实现的.

我尝试获取pbase的地址字段,然后将pderived初始化为具有该地址的新Ptr,但当然我的引用计数全部搞砸了.

我尝试创建一个新的Ptr,它引用了pderived的计数器,但后来我无法设置pderived的地址字段,所以我也被卡在那里.

我告诉你们这些信息是因为:1.我想说明一点,我在网上寻求帮助之前已经做了很长时间了2.我希望你知道我已经尝试了什么.

我真的可以在这里使用一些建议.该怎么做:

pderived = <SOMETHINGSOMETHING>pbase<SOMETHINGSOMETHING>
Run Code Online (Sandbox Code Playgroud)

谢谢!

bdo*_*lan 6

通常,智能指针类将公开动态强制转换包装器,该包装器正确处理底层智能指针对象.例如,C++ 0x具有dynamic_pointer_cast函数.请注意,您*((Ptr<Derived>*)(dynamic_cast<Ptr<Base>*>(&pbase)));可以并且将会中断,特别是如果您有多个继承,因为它不会将内部指针调整address到子类内的右偏移量以获得所需的任何超类.

在实现级别,refcounting智能指针类通常在每个智能指针中携带两个指针; 一个直接指向对象(适当地转换为指针所指的任何类型),一个指向包含引用计数,指向原始对象的指针和指向删除例程的指针的结构.这允许指针的任何已转换变体正确地返回原始对象并调用其析构函数.目前你直接指向a size_t,它没有给你这个信息.

在任何情况下,一旦你有了这个析构函数的间接性,当需要投射这些智能指针时,你可以只投射外部指针; 当破坏时间到来时,单独留下这个内部参考计数结构.

当然,将这一切全部转化为代码仍然是读者的练习:)