【问题标题】:c++: override template member function in parent classc ++:覆盖父类中的模板成员函数
【发布时间】:2013-07-11 06:28:58
【问题描述】:

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

似乎更好的解决方案是实现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 等功能。我什至计划将强制转换添加到内置对象,尽管现在我只是重载@987654339 @、operator signed short() const等。如果没有实现,模板必须从Object类切换到它的通用形式,只是抛出一个错误。有没有办法做到这一点(也许我需要使用一些模式)?或者留下Int cast_int() const之类的功能更容易?提前致谢!

【问题讨论】:

  • 如果您的数据转换存储在基类中,则没有理由不能将模板化成员函数添加到同一个基类中。然后让子类调用它。或者我可能误解了这个问题。

标签: c++ function templates virtual-functions


【解决方案1】:

添加一个中间类,如下例所示,或者只使用 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;
}

【讨论】:

    【解决方案2】:

    你所做的听起来不是一个好主意,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_;
         }
    };
    

    【讨论】:

      【解决方案3】:

      你可以保留一组标志

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

      【讨论】:

        【解决方案4】:

        如果您对运行时强制转换没问题,另一种选择。

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

        【讨论】:

          【解决方案5】:

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

          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() 来模拟任何对象。如果相等,您可以执行静态转换

          【讨论】:

            猜你喜欢
            • 2021-11-08
            • 1970-01-01
            • 2020-12-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-02-06
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多