首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >协变返回类型无效

协变返回类型无效
EN

Stack Overflow用户
提问于 2012-11-05 21:10:50
回答 2查看 10.5K关注 0票数 3

下面是一些有代表性的代码,它们得到了我遇到的错误:

代码语言:javascript
复制
class Data
{
};

class Table
{
  virtual std::vector<Data*> getData() = 0;
  virtual void putData(Data* dataItem) = 0;
  virtual Data* getData(int index) = 0;
};

class DerivedData : Data
{
};

class DerivedTable : Table
{
  std::vector<DerivedData*> getData() { return myData; } // invalid covariant return type
  void putData(DerivedData *dataItem) { myData.push_back(dataItem); }
  virtual DerivedData* getData(int index) { return myData[index]; } // invalid covariant return type

  std::vector<DerivedData*> myData;
};

首先,我不太明白为什么putData的覆盖对参数的改变很满意,但是我不能改变getData的返回类型,尽管我很欣赏这一点,我可以通过更多的阅读来理解这一点。

其次,也是我的主要问题,如何更改此代码才能使其工作。我的基本目标是允许多个类似于表的对象来存储和控制数据对象。虽然每个数据对象将共享一些共同之处,但表将控制和使用一些明显的不同之处。例如,一个表可能有一个具有name参数的数据对象,因此该表将提供一个函数,该函数打印它持有的所有数据的名称列表。这样,我就可以拥有处理所有这些表对象的通用代码,以及只处理一种类型的表的专用代码。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-11-05 21:15:22

很多事情都是错的:

  1. 这两个版本的putData是完全不同的、无关的重载。在C++中,没有用于覆盖虚函数的“逆变参数类型”(即使有,也会反过来!)。将关键字override添加到派生函数以使编译器产生错误。
  2. 类模板不按您所想的方式工作。如果template <typename T> class Foo是一个类模板,那么Foo<X>Foo<Y>是完全不同的、不相关的类,无论XY是否以任何方式相关。

正如@Beta所说,你可能只有一个简单的std::vector<std::unique_ptr<Data>>作为你的主要数据结构。但不管怎样,如果你真的需要一些层次结构,这里有一个可能的“解决方案”:

代码语言:javascript
复制
#include <memory>
#include <vector>

struct Data { virtual ~Data() { } };

struct Table
{
    virtual ~Table() { }

    typedef std::unique_ptr<Data> data_ptr;
    typedef std::vector<data_ptr> dataset_type;

    virtual dataset_type & getData() = 0;
    virtual void putData(data_ptr dp) = 0;
    virtual Data & getData(std::size_t n) = 0;
};

class DerivedTable : public Table
{
    dataset_type myData;

public:

    virtual void putData(data_ptr p) override
    {
        myData.push_back(std::move(p));
    }

    Data & getData(std::size_t n) override
    {
        return *myData[n];
    }

    // ...
};
票数 5
EN

Stack Overflow用户

发布于 2016-05-13 04:09:30

“无效的协变返回类型”实际上是由于您试图更改getData()的返回类型而导致的。虽然返回类型不是函数标识符的一部分,但它仍然受到一些限制。任何覆盖某个基类的方法都应该具有类似的行为。也就是说,虚方法实现将尝试向上转换到Data,以便为从Table* (而不是DerviedTable*)的角度调用getData()的客户端返回一个有效指针。这可以与DerviedTable::getData(int)上下文中的(Data*)myData[index]进行比较。

这正是编译器的困惑之处。

代码语言:javascript
复制
class DerivedData : Data
{
};

这个声明说DervidedData私有继承了Data 。也就是说,DerviedData的任何客户端都不“知道”它实际上是一个Data。这也使得为DerviedData* getData() override生成代码变得不可能,因为从DeviedTable::getData(int)无法向上转换到Data

为了让这个错误消失,你可以让继承对公共可见:

代码语言:javascript
复制
class DerivedData : public Data
{
};

或者交个朋友

代码语言:javascript
复制
class DerivedData : Data
{
    friend class DerivedTable;
};

尽管这种设计仍然是一个有问题的主题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13232853

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档