2013-01-04 74 views
4

這是錯誤:的類型爲std參考無效初始化::向量

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

上面Bean類是數據表示,並且它們由兩個不同的層使用。一層使用Bean接口,僅用於訪問數據的獲取者。 ResourceBean由數據訪問對象(DAO)類訪問,該類從數據庫中獲取數據(例如),並填寫ResourceBean。在DAO的

一個責任是列出的資源給予一定的路徑:

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

我認爲這個問題是一個事實,即在std::vector<ResourceBean*>編譯器不明白Bean實際上是基類相關ResourceBean

有什麼建議嗎?我已經閱讀了一些類似的主題,但一些解決方案在我的情況下不起作用。請指出我是否遺漏了一些東西。先謝謝你。

+1

在繼續之前,請注意您的代碼不是類型安全的(它是要編譯的)。一個'std :: vector '不是'std :: vector '的有效子類型(在一般LSP意義上),因爲'std :: vector '不支持所有'std :: vector '的操作(例如,您可以將任何'Bean *'放入'std :: vector '中,而您只能將'ResourceBean *'放入'std :: vector ')。 – Mankarse

+0

謝謝你的回覆。我試圖理解爲什麼你說「一個std :: vector 不支持std :: vector 所做的所有操作」。另外,當你說「你可以把任何Bean *放入std :: vector ,而你只能將一個ResourceBean *放入一個std :: vector 」時,你的意思是你可以放任何Bean * (包括*派生類)? –

+0

是的。例如,你可以**將'FooBean *'放入一個'std :: vector '(其中'FooBean'是'Bean'的某個子類),但是你**不能**放入一個'FooBean *轉換成'std :: vector '。如果某些代碼使用'Service :: list'並且期望引用'std :: vector'表示'FooBean *'可以放入,則由'DummyService ::'返回的'std :: vector '清單'是不夠的。 – Mankarse

回答

6

std::vector<Bean*>std::vector<ResourceBean*>是兩個完全不同的類型,它們不能相互轉換。你只是不能在C++中做到這一點,應該堅持一個指向基類的指針向量。另外,因爲這個功能virtual沒有做你認爲它的功能 - 不同的返回類型使它成爲一個不同的方法簽名,所以不是重載一個方法,而是引入一個新的虛擬方法。此外,無需爲抽象類(Service)保護構造函數,因爲無論如何您都無法創建抽象類的實例。我會這樣寫:

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

有道理,但Bean類不能用數據填充(因爲它只包含getter)。有什麼方法可以在DummyService的list方法中返回std :: vector &,但是在該方法中從ResourceBean轉換爲Bean? –

+0

@ user1570742:'ResourceBean',當從'Resource'繼承時,可以隱式轉換爲'Resource',它的基類。我編輯了我的答案併爲此添加了一些示例。 – 2013-01-04 14:05:20

+1

感謝您花時間解釋這一點。它現在完美。 –