简体   繁体   English

无法动态投射到PTR

[英]Cannot dynamic cast to ptr

I am trying to implement very basic class similar to boost::any, but there is a problem I am facing with and I cannot overpass this. 我正在尝试实现类似于boost :: any的非常基本的类,但是我面临着一个问题,我不能超越它。 Problem is with casting pointer to another using dynamic_cast with error saying: 问题是使用dynamic_cast将指针强制转换为另一个指针,错误提示:

cannot dynamic_cast 'input.Any::m_targetPtr' (of type 'class Any::StorageInterface*') to type 'int*' (target is not pointer or reference to class)

source of class is as follows: 类的来源如下:

class Any{
public:
    template <typename T>
    Any(T input): m_targetPtr(new StorageImpl<T>(input)){}
    ~Any(){delete m_targetPtr;}

    class StorageInterface{
    public:
        virtual ~StorageInterface(){}
    };

    template<typename T>
    T* cast(Any& input){
        return dynamic_cast<T*>(input.m_targetPtr); //here comes the trouble
    }

    template <typename T>
    class StorageImpl : public StorageInterface{
    public:
        StorageImpl(T& input): m_target(&input){}
        T* m_target;
    };

    StorageInterface* m_targetPtr;
};

and this is how I want to execute this: 这就是我要执行的方法:

int i=150;
Any asdf(i);
cout<< (asdf.cast<int>(asdf)) << endl;

So my understanding is. 所以我的理解是。 I have an int variable and to the cast template I pass pointer to this int and T in template is int, therefore in the cast source we have int as deduced parameter int* as returning value and I execute dynamic_cast<int*> with argument m_target of type StorageInterface* . 我有一个int变量,并且我向cast模板传递了指向此int的指针,而模板中的T是int,因此在演员表源中,我们将int作为推导参数int*作为返回值,并使用参数m_target执行dynamic_cast<int*>类型为StorageInterface* Why then I am getting an error, that my target is not a pointer? 为什么然后我得到一个错误,即我的目标不是指针?

I see the following problems in the following code. 我在以下代码中看到以下问题。

template<typename T>
T* cast(Any input){
    return dynamic_cast<T*>(input.m_targetPtr); //here comes the trouble
}
  1. You need to cast to StorageImpl<T>* , not T* . 您需要StorageImpl<T>*转换为StorageImpl<T>* ,而不是T*

  2. StorageImpl doesn't expose its member, m_target . StorageImpl不公开其成员m_target

Expose the m_target member, by making it public or providing a function that returns the value. 露出m_target构件,通过使public或提供一个返回值的函数。

Change the cast function to: cast功能更改为:

template<typename T>
T* cast(Any input){
    return dynamic_cast<StorageImpl<T>*>(input.m_targetPtr)->m_target;
}

Suggestion for improvement: 改进建议:

You don't need the input argument in cast . 您不需要在cast使用input参数。 It can be: 有可能:

template<typename T>
T* cast(){
    return dynamic_cast<StorageImpl<T>*>(m_targetPtr)->m_target;
}

Then, your call can also be simplified to: 然后,您的通话也可以简化为:

cout<< (asdf.cast<int>()) << endl;
                  //  ^^^ No need to use asdf again in the call.

Suggestions for further improvement 进一步改进的建议

The StorageImpl in your posted code stores a pointer to an object that can easily become invalid. 您发布的代码中的StorageImpl存储了指向很容易变得无效的对象的指针。 I would recommend storing an object instead. 我建议改为存储一个对象。 Then, Any::cast() can return a reference instead of a pointer. 然后, Any::cast()可以返回引用而不是指针。

class Any {
   public:
      template <typename T>
         Any(T input): m_targetPtr(new StorageImpl<T>(input)){}
      ~Any(){delete m_targetPtr;}

      class StorageInterface {
         public:
            virtual ~StorageInterface(){}
      };

      template<typename T>
         T const& cast() const {
            return dynamic_cast<StorageImpl<T>*>(m_targetPtr)->m_target;
         }

      template<typename T>
         T& cast() {
            return dynamic_cast<StorageImpl<T>*>(m_targetPtr)->m_target;
         }

      template <typename T>
         class StorageImpl : public StorageInterface {
            public:
               StorageImpl(T const& input): m_target(input){}
               T m_target;
         };

      StorageInterface* m_targetPtr;
};

The issue is that dynamic_cast<T>(X) cannot convert type X to type T if X doesn't belong in the same class hierarchy as T . 的问题是, dynamic_cast<T>(X)无法转换型X为类型T如果X不相同的类层次结构作为属于T Dynamic cast is meant for polymorphism, for down-casting Animal* to Dog* , for example, where class Dog inherits from class Animal and class Animal contains a virtual function. 动态强制转换用于多态性,例如将Animal*向下转换为Dog* ,例如,其中class Dog继承自class Animal class Animal包含一个虚函数。 The problem is that int is not a class type, so dynamic_cast can conclude early that int and StorageInterface don't share a class heirarchy. 问题在于int不是类类型,因此dynamic_cast可以早点得出结论intStorageInterface不共享类继承。

The error message is not saying that your target is not a pointer, it's saying that your target is not a pointer to a class object (and isn't a reference to a class object either). 错误消息不是说您的目标不是指针,而是说您的目标不是指向类对象的指针(也不是对类对象的引用)。

R Sahu makes the point that you meant to cast to StorageImpl<T>* , which makes a lot more sense. R Sahu指出了要转换为StorageImpl<T>* ,这更有意义。

dynamic_cast<T> is intended to use to convert a pointer to a polymorphic struct to another polymorphic struct in the same hierarchy. dynamic_cast<T>旨在用于将指向多态结构的指针转换为同一层次结构中的另一个多态结构。 A polymorphic struct is a struct with at least one virtual function or virtual inheritance. 多态结构是具有至少一个虚拟函数或虚拟继承的结构。 Clearly, int* is not a struct and is not polymorphic. 显然,int *不是结构,也不是多态的。

You probably meant to make this cast instead: 您可能打算改成这个演员表:

template<typename T>
T* cast(Any input){
    return dynamic_cast<StorageImpl<T>*>(input.m_targetPtr)->m_target; // better?
}

And why sending a copy of the object to itself? 以及为什么将对象的副本发送给自己呢? I would be less error-prone to limit the function to the instance itself: 我将不太容易将函数限制为实例本身:

template<typename T>    
T* cast(){
    return dynamic_cast<StorageImpl<T>*>(m_targetPtr)->m_target; // even better
}

You can use it like this now: 您现在可以像这样使用它:

asdf.cast<int>();

Finally, to make your code even cleaner and less error prone, one last thing could be done. 最后,为使您的代码更清晰,更不易出错,可以做最后一件事。 Did you see the potential undefined behaviour? 您是否看到了潜在的不确定行为? You have a double deletion in you code: 您的代码中有两次删除:

template<typename T>
T* cast(Any input){
    return dynamic_cast<T*>(input.m_targetPtr); //here comes the trouble
    // input is deleted here, so asdf will have a dangling pointer and double delete the m_targetPtr!
}

And in your constructor, you save the address of a temporary: 在您的构造函数中,保存一个临时地址:

// input is a reference to a variable from the 'Any' class constructor, it will be deleted
StorageImpl(T& input): m_target(&input){}

Passing by value (and move) could fix this. 通过传递值(并移动)可以解决此问题。

Any code using this class is subject to these error. 使用此类的任何代码都将受到这些错误的影响。 Using a std::unique_ptr and value semantics will do the trick: 使用std::unique_ptr和值语义可以解决问题:

struct Any {
    template <typename T>
    Any(T input): m_targetPtr(new StorageImpl<T>(std::move(input))){}
    /* ~Any(){delete m_targetPtr;} */
    // no destructor needed here, you can safely remove the line above.

    // you could implement a copy constructor which clone the m_targetPtr.

    class StorageInterface{
    public:
        virtual ~StorageInterface(){}
    };

    template<typename T>
    T& cast(){
        return dynamic_cast<StorageImpl<T>*>(m_targetPtr.get())->m_target;
    }


    template <typename T>
    class StorageImpl : public StorageInterface{
    public:
        StorageImpl(T input): m_target(std::move(input)){}
        T m_target;
    };

private:
    std::unique_ptr<StorageInterface> m_targetPtr;
};

This code will require T to be moveable. 此代码将要求T是可移动的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM