【问题标题】:Array of template objects模板对象数组
【发布时间】:2011-08-16 02:41:54
【问题描述】:

我不知道如何解决模板和继承问题。

在我的代码中有一个模板类,看起来或多或少像:

template<typename T>
class Derived : public Base{
     T value;
public:
     Derived(T arg) { value=arg; };
     T getValue() { return value;};
};

class Base{
};

我的 Base 类的唯一目的是对 Derived 类的对象数组进行分组。参数 T 通常是 double、float 或 complex,尽管 int 和 structs 也可能有用。 (稍后应该会有更多类似的派生类,并带有一些附加功能。)

我可以创建这样的组

Base** M = new Base*[numElements];

并将派生类的元素分配给它们,例如:

M[54] = new Derived<double>(100.);

但是我怎样才能知道第 55 个元素的值是 100 呢? 我需要类似的东西

virtual T getValue() = 0;

但是 T 是派生类的类型名,对于这个数组的任意两个元素可能不同。

【问题讨论】:

标签: c++ templates polymorphism


【解决方案1】:

将方法“getDouble”添加到您的基类。然后,派生类必须实现此方法,并在需要时将自己的类型转换为 double。

【讨论】:

  • 如果不是双精度怎么办?如果它的 int/float 或 string 怎么办?由于基类没有模板化,有可能吗?
【解决方案2】:

您可以使用 dynamic_cast 来了解它是什么类型(除了 @StackedCrooked 所说的)。 它需要在基类中定义一些虚函数,但您已经需要一个虚析构函数(能够通过基类指针删除值)。

作为替代方案,您可以尝试 boost::variant 或 boost::any :)

【讨论】:

    【解决方案3】:

    没有。实际上不可能有这样的功能,原因有两个:

    1. Base 不能是模板,因为你 想要一个通用句柄来存储 可以包含任何类型的数组 Derived 喜欢 <int>, <double>, <float>, any struct <abc>
    2. Base 内不能有template virtual 方法, 因为语言不允许

    解决这个问题的简单方法是为get_double()get_int()get_float()get_abc() 等每种类型设置“getter”方法。但是,您的Base 会被这些方法弄得一团糟。

    【讨论】:

      【解决方案4】:

      Visitor 模式可能是您最好的选择。迭代数组的代码必须提供一个知道如何处理各种类型的“Visitor”对象。

      struct NumericVisitor
      {
          virtual void visit(double) = 0;
          virtual void visit(int) = 0;
          virtual void visit(unsigned char) = 0;
      };
      
      struct Visitable
      {
          virtual void visitValue(NumericVisitor& visitor) = 0;
      };
      
      template<typename T>
      class Derived : public Visitable
      {
           T value;
      public:
           Derived(const T& arg) value(arg) {}
           void visitValue(NumericVisitor& visitor) { visitor.visit(value); }
      };
      

      现在您可以为要对集合执行的每个操作定义访问者,例如将每个元素转换为字符串,为每种类型使用不同的格式,或者将每个元素存储到一个文件中,其中每种类型可以占用不同的空间量。

      【讨论】:

      • 您好 Ben,感谢您对我的第一个问题的回复。我相信你是这个论坛上最伟大的专家之一,使用访问者模式看起来比在不知道使用哪个类型的情况下为所有类型添加 getter 函数更有希望。虽然,我必须承认我并不完全理解它,然而。它做我想要的吗?用我原来的方法似乎已经可以将元素转换为字符串或将元素存储到文件中,但我是否也克服了剩余的困难?
      • @Max:当然可以将任何操作作为虚函数添加到 Base 类中。访问者模式的作用是(1)添加新操作而不使 class Base 混乱和(2)克服对成员函数模板特化的限制(你不能特化模板类的成员,你必须特化整个类) .我认为Visitor 会满足您的需求,但是您的示例用法“找出元素的值是 100”还不够清楚,我无法为您写一个很好的示例。
      • @Ben:示例用法很简单:基类指针已知,我想在不知道其类型的情况下检索派生类的成员变量的值。我想没有简单的方法。 (也许,在某些年份可能允许在基类中编写code virtual auto getValue()`?)
      • @Max:这不是用法。检索该值没有用,除非您对该值执行某些操作。否则我可以给你一个void* 的值。举一个你想对值做的事情的例子,然后我可以给出更好的示例代码。
      • @Max:Derived 类的目的是包含需要求解偏微分方程的程序的边界条件。我想我会为不同的类型和一个请求类型的 get() 函数添加一些。或者,我可以写void doSomething(Matrix &amp;LHS, Vector&amp; rhs)
      【解决方案5】:

      使用 boost::any 将对象存储在数组中。然后当你想对其进行操作时,你可以将 boost::any_cast 用于你可能拥有的类型。

      【讨论】:

        【解决方案6】:

        您可以将重载的 has_value() 方法添加到 Base 类:

        class Base
        {
        public:
            virtual ~Base () {}
            virtual bool has_value (int i) {return false;}
            virtual bool has_value (double d) {return false;}
            virtual bool has_value (const std::string& s) {return false;}
            // etc.
        };
        

        您在 Derived 类中覆盖的其中一个:

        template<typename T>
        class Derived : public Base
        {
             T value;
        public:
             Derived(T arg) {value=arg;}
             T getValue() { return value;}
        
             virtual bool has_value (T t)
             {
                 return t == value;
             }
        };
        

        例如:

        bool test ()
        {
            std::vector<Base*> bases;
            bases.push_back (new Derived<double> (1.234));
            bases.push_back (new Derived<int> (100));
            bases.push_back (new Derived<std::string> ("zap"));
        
            for(std::vector<Base*>::const_iterator iter = bases.begin (); iter != bases.end (); ++iter)
                if ((*iter)->has_value (100))
                    return true;
            return false;
        }
        

        请注意,您不能将 Base 类中的 has_value 方法替换为单个模板化方法,因为虚拟方法无法模板化。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-11-16
          • 2012-02-09
          • 2018-12-23
          • 1970-01-01
          • 2018-01-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多