c ++:覆盖父类中的模板成员函数

时间:2013-07-11 06:28:59

标签: c++ function templates virtual-functions

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

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

5 个答案:

答案 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()来模拟任何对象。如果它相等,你可以执行静态投射