c++:重写父类中的模板成员函数



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

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

像下面的例子一样添加一个中间类,或者只使用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;
}

您正在做的事情听起来不是一个好主意,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_;
     }
};

您可以保留一组标志

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

并在每个类中保留一个virtual int castable() const函数,例如您的Int::castable()将返回intable | floatable | doublable | stringable。并且YOu需要有另一个模板化映射,该映射采用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);
  }
}

如果您对运行时强制转换很满意,另一种选择。

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_;
    }
}

您可以为对象创建一个类型包装器。

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(

最新更新