具有向量类向量的类的下标运算符重载必须返回派生类

时间:2015-12-15 16:57:27

标签: c++ c++11 vector overloading

所以,问题可能有点令人困惑,但让我解释一下。

我有一个包含3个其他类和向量的类。 3个类中的2个继承自第三个类,向量用shared_ptr

填充
class top_class
{
     class Base
     {};

     class Derived1 : public Base
     {};

     class Derived2 : public Base
     {};

std::vector<std::shared_ptr<Base>> my_vector;
};

我想创建一个下标运算符重载,它返回对Derived1或Derived2的引用,具体取决于我被要求的元素的类型。

我一直在尝试使用auto,但我对c ++ 11很新,而且我还没有完全使用它。

请记住,我被要求以这样的方式交付它,用户应该像这样调用下标运算符:

top_class tc;
Derived1 d1 = tc[ 0 ];
Derived2 d2 = tc[ 1 ];

因此使用模板化函数不是解决方案。我目前的尝试是:

auto operator[](int index) -> decltype(*my_vector[index])
{
    return *my_vector[index];
}

但是当然这不起作用,因为我传递给decltype的类型是Base。

3 个答案:

答案 0 :(得分:1)

您无法根据某些运行时状态返回变量类型。您可以做的是要求用户提供他想要的类型并使用std::dynamic_pointer_cast

template <class Derived>
std::shared_ptr<Derived> get(size_t idx) const
{
    return std::dynamic_pointer_cast<Derived>(my_vector[idx]);
}

如果你想要抛出它,你可以检查结果是否为null并且适当地抛出:

template <class Derived>
std::shared_ptr<Derived> get(size_t idx) const
{
    auto res = std::dynamic_pointer_cast<Derived>(my_vector[idx]);
    if (!res) throw ...;
    return res;
}

此时,我们也可以使用vector::at()来投掷。

答案 1 :(得分:1)

给定成员变量

std::vector<std::shared_ptr<Base>> my_vector;

如果不执行动态转换,就无法从中获取派生类型的对象。

一旦引入动态强制转换,您将需要考虑动态强制转换的失败。此时,您必须在设计/实施中考虑以下因素。

  1. 当动态转换失败时,您是要抛出异常,还是要返回等同于nullptr的内容?

  2. 您想如何调用该功能?派生类型必须作为模板参数传递。如果您选择使用operator[],则需要使用

    调用它
    auto ret = obj.operator[]<DerivedType>(index);
    

    这种语法对我来说非常难看。也许像std::vector::at这样的东西会更合适。

    auto ret = obj.at<DerivedType>(index);
    

    在任何一种情况下,函数的返回类型将取决于您想要如何处理失败。

  3. 如果您选择抛出异常,则需要以下内容:

    template <typename DerivedType>
    DerivedType& at(size_t index)
    {
       std::shared_ptr<Base> ptr = my_vector.at(index);
       dynamic_cast* derived_ptr = dynamic_cast<DerivedType>(ptr.get());
       if ( derived_ptr == nullptr )
       {
          throw std::bad_cast();
       }
       return *derived_ptr;
    }
    

    如果您选择在动态广告投放失败时返回nullptr,则您需要以下内容:

    template <typename DerivedType>
    DerivedType* at(size_t index)
    {
       std::shared_ptr<Base> ptr = my_vector.at(index);
       return dynamic_cast<DerivedType>(ptr.get());
    }
    

    请注意,如果std::vector::at超出范围,index会抛出异常。

答案 2 :(得分:0)

由于C ++中的返回类型是指定的编译时,因此有些不寻常的语法

top_class tc;
Derived1 d1 = tc[ 0 ];
Derived2 d2 = tc[ 1 ];

很难实现(更简单就像

Derived1 d1 = tc.get<Derived1>(0);
Derived2 d2 = tc.get<Derived2>(1);
top_class::get<>知道要返回的内容时

。使用原始语法,top_class::operator[]必须返回可转换为Derived1Derived2的内容。据我所知,唯一的可能性是Base,如果Derived1Derived2都允许Base进行构建:

struct top_class
{
  struct Base { /* ... */ };
  struct Derived1 : Base
  {
    Derived1(Base const&);
    // ...
  };
  struct Derived2 : Base
  {
     Derived2(Base const&);
    // ...
  };
  Base const&operator[](std::size_t i) const
  {
    return *(data.at(i));
  }
private:
  std::vector<std::shared_ptr<Base>> data;
};