假设我有这样的类结构:基类Object
,它是Bool
的父类,Int
,Float
,Bytes
和Unicode
课程。在我将Bool cast_bool() const
,Int cast_int() const
等函数作为Object
类和所有子类中的虚函数之前,我已经分别实现了这些函数。
似乎更好的解决方案是实现template <typename TYPE> TYPE cast() const
功能。但是,由于C ++禁止虚拟模板功能,我不知道如何完成此任务。我需要的是为template <typename TYPE> TYPE cast() const
及其孩子提供Object
。通用Object::cast<TYPE>() const
只会抛出CastError
;然后针对Bool
,Int
等所有类型,我将实现Bool::cast<Bool>() const
,Int::cast<Bool>() const
等函数。我甚至计划向内置对象添加强制转换,虽然现在我只是重载operator bool() const
,operator signed short() const
等。如果没有实现,模板必须从Object
类切换到它的通用形式,只是抛出一个错误。有没有办法做到这一点(也许我需要使用一些模式)?或者更容易留下像Int cast_int() const
这样的功能?提前谢谢!
答案 0 :(得分:3)
添加如下例所示的中间类,或者只使用dynamic_cast
而不使用任何模板方法。
#include <iostream>
#include <string>
using namespace std;
template <class> class ObjectImpl;
class Object
{
public:
virtual ~Object() {}
template <class T>
T cast() const
{
if (auto obj = dynamic_cast<const ObjectImpl<T>*>(this))
{
return obj->cast();
}
else
{
throw std::string("cast error");
}
}
};
template <class T>
class ObjectImpl : public Object
{
public:
virtual T cast() const = 0;
};
class Bool : public ObjectImpl<bool>
{
public:
bool cast() const override { return true; }
};
class Float : public ObjectImpl<float>
{
public:
float cast() const override { return 12.34f; }
};
int main()
{
Object* obj = new Float;
cout << obj->cast<float>() << endl;
try
{
cout << obj->cast<bool>() << endl;
}
catch (std::string e)
{
cout << e << endl;
}
return 0;
}
答案 1 :(得分:0)
你在做什么听起来不是一个好主意,C ++不是Java或C#......不过你可以这样做:
class Object
{
public:
template<typename T>
T& cast()
{
return cast_impl(std::declval<T>());
}
private:
virtual bool& cast_impl(bool&){ throw std::bad_cast(); }
virtual int& cast_impl(int&){ throw std::bad_cast(); }
};
class Boolean : public Object
{
bool value_;
public:
private:
bool& cast_impl(bool) override
{
return value_;
}
};
答案 2 :(得分:0)
你可以保留一组标志
enum Castablity{
intable = 0x1,
floatable = 0x2,
doubleable = 0x4,
bytable = 0x8,
stringable = 0x10,
unicodable = 0x20,
};
并在每个类中保留virtual int castable() const
函数,例如您的Int::castable()
将返回intable | floatable | doublable | stringable
。并且你需要有另一个模板化的地图,它采用Castablity枚举值并返回typedef中的目标类型。
template <typename T>
struct type_value;
template <enum v>
struct value_type;
template <>
struct type_value<Int>{
enum {value = intable;}
};
template <>
struct value_type<intable>{
typedef Int data_type;
};
和全局演员函数
template <typename T, typename U>
U cast(const T& original){
if(!original.castable(type_value<U>::value))
//throw exception
return detail::cast<U>(original.internal_data());
}
您可以使用一个虚方法,该方法采用整数值而不是在编译时获取类型。或者你可以有一个内部结构来存储所有类型的对象值。像boost::any
您可以在详细命名空间中编写另一个专门化,将该内部类型转换为目标类型
namespace detail{
template <typename T>
/// you may have specialization for different types
struct casting_helper{
static T cast(const internal_type& data){
}
}
template <typename T>
T cast(const internal_data& data){
return casting_helper<T>::cast(data);
}
}
答案 3 :(得分:0)
如果您对运行时强制转换没有问题,则另一种选择。
class Object
{
public:
template<typename T>
T& cast()
{
return *dynamic_cast<T*>(get());
}
private:
virtual void* get() = 0;
};
class Boolean : public Object
{
bool value_;
public:
private:
void* get() override
{
return &value_;
}
}
答案 4 :(得分:0)
您可以为对象创建一个类型包装器。
struct TypeWrapperBase
{
protected:
static int m_counter;
};
int TypeWrapperBase::m_counter = 0;
template<typename T>
struct TypeWrapper:
TypeWrapperBase
{
static int m_type;
protected:
static int AllocateType()
{
m_counter++;
return m
}
public:
static int GetType()
{
return m_type;
}
};
template<typename T>
int TypeWrapper<T>::m_type = TypeWrapperBase::m_counter++;
void main()
{
std::cout << TypeWrapper<int>::GetType() << std::endl; // prints 0
std::cout << TypeWrapper<float>::GetType() << std::endl; // prints 1
std::cout << TypeWrapper<bool>::GetType() << std::endl; // prints 2
}
现在,您可以通过比较el1.GetType()和el2.GetType()来模拟任何对象。如果它相等,你可以执行静态投射