我正在尝试实现类似于boost :: any的非常基本的类,但是我遇到了一个问题,我无法绕过它。问题是使用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)
课程来源如下:
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;
};
这就是我想要执行的方式:
int i=150;
Any asdf(i);
cout<< (asdf.cast<int>(asdf)) << endl;
所以我的理解是。我有一个int
变量,而cast
模板我将指针传递给此int,模板中的T
为int,因此在强制转换源中我们有int
作为推导参数int*
作为返回值,我使用dynamic_cast<int*>
类型的参数m_target
执行StorageInterface*
。为什么然后我收到错误,我的目标不是指针?
答案 0 :(得分:2)
我在以下代码中看到以下问题。
template<typename T>
T* cast(Any input){
return dynamic_cast<T*>(input.m_targetPtr); //here comes the trouble
}
您需要投放到StorageImpl<T>*
,而不是T*
。
StorageImpl
未公开其成员m_target
。
公开m_target
成员,使其成为public
或提供一个返回值的函数。
将cast
功能更改为:
template<typename T>
T* cast(Any input){
return dynamic_cast<StorageImpl<T>*>(input.m_targetPtr)->m_target;
}
建议改进:
input
中不需要cast
参数。它可以是:
template<typename T>
T* cast(){
return dynamic_cast<StorageImpl<T>*>(m_targetPtr)->m_target;
}
然后,您的通话也可以简化为:
cout<< (asdf.cast<int>()) << endl;
// ^^^ No need to use asdf again in the call.
进一步改进的建议
发布的代码中的StorageImpl
存储指向容易变为无效的对象的指针。我建议改为存储一个对象。然后,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;
};
答案 1 :(得分:1)
问题在于dynamic_cast<T>(X)
如果T
与[{1}}属于同一类层次结构,则无法将类型X转换为X
类型。动态强制转换用于多态,用于向下转换T
到Animal*
,例如,Dog*
继承自class Dog
而class Animal
包含虚函数。问题是class Animal
不是类类型,因此int
可以提前得出结论dynamic_cast
和int
不要共享类层次。
错误消息并不是说您的目标不是指针,而是说您的目标不是指向类对象的指针(并且也不是对类对象的引用)。< / p>
R Sahu明确指出你要转向StorageInterface
,这更有意义。
答案 2 :(得分:1)
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(ACDFilterCollectionViewCellConstants.CellIdentifier, forIndexPath: indexPath) as! ACDFilterCollectionViewCell
let filterType = filters[indexPath.row]
cell.titleLabel.text = filterType.rawValue
let skview = SKView(frame: cell.frame)
cell.filterView.addSubview(skview)
return cell
}
旨在用于将指向多态结构的指针转换为同一层次结构中的另一个多态结构。多态结构是具有至少一个虚函数或虚继承的结构。显然,int *不是结构体,也不是多态的。
你可能打算改为演员:
dynamic_cast<T>
为什么要将对象的副本发送给自己?我不太容易将函数限制为实例本身:
template<typename T>
T* cast(Any input){
return dynamic_cast<StorageImpl<T>*>(input.m_targetPtr)->m_target; // better?
}
您现在可以这样使用它:
template<typename T>
T* cast(){
return dynamic_cast<StorageImpl<T>*>(m_targetPtr)->m_target; // even better
}
最后,为了使您的代码更清晰,更不容易出错,最后还是可以完成。您是否看到了潜在的未定义行为?您的代码中有双重删除:
asdf.cast<int>();
在构造函数中,您保存临时的地址:
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!
}
按值传递(和移动)可以解决这个问题。
使用此类的任何代码都会受到这些错误的影响。使用// input is a reference to a variable from the 'Any' class constructor, it will be deleted
StorageImpl(T& input): m_target(&input){}
和值语义可以解决这个问题:
std::unique_ptr
此代码将要求T可移动。