4

This is the error:

DummyService.hpp:35: error: invalid covariant return type for 'virtual std::vector < ResourceBean*, std::allocator < ResourceBean*> >& DummyService::list(const std::string&)'

class Bean {
public:
    typedef std::string Path;
    virtual ~Bean() {};
    virtual const Path& getPath() = 0;
    virtual const std::string& getName() = 0;
protected:
    Bean();
};

class ResourceBean: public Bean {
public:
    ResourceBean(const Path& path, const std::string& contents) :
            _path(path), _contents(contents) {
    }
    virtual ~ResourceBean() { }
    virtual const Path& getPath();
    virtual void setPath(const Path& path);
    virtual const std::string& getName();
    virtual void setName(const std::string& name);
private:
    Path _path;
    std::string _name;
};

The above Bean classes are data representations, and they are used by two different layers. One layer uses the Bean interface, just to access the getters for the data. The ResourceBean is accessed by the data access object (DAO) classes, which take the data from a database (for example), and fill in the ResourceBean.

One responsibility of the DAO is to list the resources given a certain path:

class Service {
protected:
    /*
     * Service object must not be instantiated (derived classes must be instantiated instead). Service is an interface for the generic Service.
     */
    Service();

public:
    virtual std::vector<Bean*>& list(const Bean::Path& path) = 0;
    virtual ~Service();
};

class DummyService: public Service {
public:
    DummyService();
    ~DummyService();

    virtual std::vector<ResourceBean*>& list(const ResourceBean::Path& path);
};

I think the problem is related with the fact that in std::vector<ResourceBean*> the compiler does not understand that Bean is actually the base class of ResourceBean.

Any suggestions? I've read to some similar topics but some of the solutions did not work in my case. Please point out if I have missed something. Thank you in advance.

4

1 に答える 1

6

std::vector<Bean*> and std::vector<ResourceBean*> are two completely distinct types that are not convertible to each other. You simply cannot do that in C++ and should stick with a vector of pointer to the base class instead. Also, because of that, having that function virtual is not doing what you think it does — different return types make it a different method signature so instead of overloading a method, you introduce a new virtual method. Also, there is no need to make a constructor protected for an abstract class (Service) because you cannot create instance of an abstract class anyway. I'd write it something like this:

#include <string>
#include <vector>
#include <iostream>

class Bean {
  public:
    typedef std::string Path;

    Bean() {}
    virtual ~Bean() {}

    virtual void say() const
    {
        std::cout << "I am a bean!\n";
    }
};

class ResourceBean : public Bean {
  public:
    ResourceBean() {}
    virtual ~ResourceBean() {}

    virtual void say() const
    {
        std::cout << "I am a resource bean!\n";
    }
};

class Service {
public:
    Service() {}
    virtual ~Service() {}

    virtual std::vector<Bean*>& list(const Bean::Path &path) = 0;
};

class DummyService: public Service {
  public:
    DummyService()
    {
        for (int i = 0; i < 5; ++i)
            beans_.push_back(new ResourceBean());
    }

    virtual ~DummyService() {}

    virtual std::vector<Bean *>& list(const Bean::Path &path)
    {
        return beans_;
    }

  private:
    std::vector<Bean*> beans_;
};

int main()
{
    DummyService s;
    std::vector<Bean *>& l = s.list("some path");
    for (std::vector<Bean *>::iterator it = l.begin(), eit = l.end();
         it != eit; ++it)
    {
        Bean *bean = *it;
        bean->say();
    }
}
于 2013-01-04T13:48:54.213 に答える