Несовместимые экземпляры шаблона - PullRequest
0 голосов
/ 27 июня 2018

У меня есть два интерфейса:

class IElement
{
    public:
    virtual ~IElement() {}
};
class IContainer
{
    public:
    virtual ~IContainer() {}
    virtual const std::vector<IElement *> &elements() const = 0;
};

Член elements из IContainer должен возвращать вектор указателей в IElement.

Тогда у меня есть две конкретные реализации:

class CConcreteElement: public IElement
{
    public:
    virtual ~CConcreteElement() {}
    void doSomething() { /* ... */ }
};
class CConcreteContainer: public IContainer
{
    private:
    std::vector<CConcreteElement *> m_vecElements;

    public:
    virtual ~CConcreteContainer() {}
    virtual const std::vector<IElement *> &elements() const override
        { return m_vecElements; }  // PROBLEM HERE
    void doSomething()
    {
        for (CConcreteElement *pE : m_vecElements)
        {
            pE->doSomething();
        }
    }
};

Выше не компилируется, потому что m_vecElements имеет тип const std::vector<CConcreteElement *>, а возвращаемое значение должно иметь тип const std::vector<IElement *>. Очевидно, C ++ не осознает, что типы IElement и CConcreteElement связаны, когда они появляются в качестве аргумента шаблона.

Я тоже пробовал:

return static_cast<const std::vector<IElement *>>(m_vecElements);

Но это тоже не компилируется. Любые идеи, как я мог заставить это работать?

1 Ответ

0 голосов
/ 27 июня 2018

Вы не можете выполнить это приведение, потому что std::vector является инвариантом для его типа элемента, что означает отсутствие связи (в смысле наследования) между различными векторами, даже если их элементы связаны. Для получения дополнительной информации о типовой дисперсии см. эту статью .

Краткий ответ: вы не можете сделать эту точную вещь с std::vector, но вы можете сделать это, предоставив элемент getter вместо все элементы getter :

class IContainer
{
public:
    virtual ~IContainer() {}
    virtual const IElement *element(size_t index) const = 0;
};

class CConcreteContainer: public IContainer
{
private:
    std::vector<CConcreteElement *> m_vecElements;

public:
    virtual ~CConcreteContainer() {}
    virtual const CConcreteElement *element(size_t index) const override
    {
        return m_vecElements[index];
    }
};

Обратите внимание, что тип возвращаемого значения метода переопределения отличается от базового метода. Это возможно, потому что C ++ поддерживает ковариантные возвращаемые типы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...