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



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

我有一个包含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。

您不能基于某些运行时状态返回变量类型。您可以要求用户提供他想要的类型并使用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()来投掷。

给定成员变量

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

    无论哪种情况,函数的返回类型都将取决于您希望如何处理失败。

如果你选择抛出异常,你需要这样的东西:

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

请注意,如果index超出范围,std::vector::at将引发异常。

由于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;
};

最新更新