1

假设我有这样一个类结构:基类Object,它是BoolIntFloat和类Bytes的父Unicode类。在我在类和所有子类中将一些函数(如Bool cast_bool() constInt cast_int() const等)作为虚函数之前,Object我已经分别实现了这些函数。

似乎更好的解决方案是实现template <typename TYPE> TYPE cast() const功能。但是,由于 C++ 禁止虚拟模板功能,我不知道如何才能完成这项任务。我需要的是提供template <typename TYPE> TYPE cast() constObject它的孩子。泛型Object::cast<TYPE>() const只会抛出CastError;然后对于每种类型,如BoolInt等。我将实现,等函数Bool::cast<Bool>() constInt::cast<Bool>() const我什至计划将强制转换添加到内置对象,尽管现在我只是重载operator bool() constoperator signed short() const等。如果没有实现,模板必须切换到它来自类的通用形式Object,只是抛出一个错误。有没有办法做到这一点(也许我需要使用一些模式)?或者更容易留下类似的功能Int cast_int() const?提前致谢!

4

5 回答 5

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;
}
于 2013-07-11T06:50:21.230 回答
0

您可以保留一组标志

enum Castablity{
    intable    = 0x1,
    floatable  = 0x2,
    doubleable = 0x4,
    bytable    = 0x8,
    stringable = 0x10,
    unicodable = 0x20,
};

virtual int castable() const并在每个类中保留一个函数,例如您的Int::castable()将 return 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);
  }
}
于 2013-07-11T06:44:15.493 回答
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_;
    }
}
于 2013-07-11T07:43:06.570 回答
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_;
     }
};
于 2013-07-11T06:40:36.920 回答
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() 来模拟任何对象。如果相等,您可以执行静态转换

于 2015-05-04T07:54:11.970 回答