Защищенные члены зависимых шаблонных баз - PullRequest
0 голосов
/ 04 июня 2018

Итак, я прочитал этот вопрос, и я понимаю предпосылку зависимых имен в шаблонах и то, как вы должны иногда квалифицировать метод с помощью this->, чтобы компилятор мог правильно его найтиОднако я столкнулся со сценарием, который я не могу понять, как решить.В частности, когда объект, которому принадлежит метод, относится к тому же типу, что и *this, но это другой объект (потенциально другого подкласса).Например:

#include <iostream>

template<class T>
class A
{
protected:
    virtual void foo() = 0;
};

template<class T>
class B : public A<T>
{
};

template<class T>
class C : public B<T>
{
protected:
    void foo() override
    {
        std::cout << "Hello, world" << std::endl;
    }
};

template<class T>
class D : public B<T>
{
protected:
    void foo() override
    {
        B<T> *b = new C<T>();
        b->foo(); // error: 'void A<T>::foo() [with T = int]' is protected
    }
public:
    void bar()
    {
        this->foo();
    }
};

int main()
{
  D<int> d;
  d.bar();
}

Учитывая эту иерархию наследования и ошибку при вызове b->foo();, каким будет правильный способ вызова этой функции?Как я понимаю, он должен быть в принципе доступен для кода в D, так как он является защищенным членом базового класса, но это усложняется системой шаблонов.

1 Ответ

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

Ваша проблема не имеет ничего общего с шаблонами и выдает ту же ошибку, если вы удаляете весь шаблонный код.

Объявление элемента как protected означает, что вы можете получить доступ только к этому элементуиз того же (прямого) класса;таким образом, хотя D и C могут оба получать из B, они оба являются совершенно разными типами, а не напрямую a B, таким образом D и C не может получить доступ к защищенным членам другого экземпляра B.

В качестве примера, возьмите следующий код, используя часть вашего опубликованного кода:

class D : public B
{
    public:
        void baz(D& d, B& b)
        {
            foo(); // ok: calls this->foo();
            d.foo(); // ok: type of `d` is `D`, same class
            b.foo(); // error: can't access protected member
        }
};

В вашем коде изменение B* b = new C(); на B* b = new B(); в классе D будет по-прежнемуполучить ту же ошибку при попытке доступа к защищенному члену.Если вы измените его на D* b = new D();, то ошибка исчезнет, ​​потому что b теперь того же типа, что и класс, в котором он находится.

Чтобы устранить эту ошибку, вы можете объявить D другом B, но при этом возникают и другие проблемы, которые необходимо учитывать, вы должны добавить объявление пересылки / друга для каждого класса, к которому вы хотите иметь доступ к foo, следующим образом:

template < class T >
class D;

template <class T>
class B : public A<T>
{
    friend class D<T>;
};

Однако,учитывая код, который вы выложили, можно было бы вместо этого переместить функцию bar из D и поместить ее в B, тогда вам не придется гадить с предварительными объявлениями, и большая часть вашего кода останетсято же самое:

template <class T>
class B : public A<T>
{
public:
    void bar()
    {
        this->foo();
    }
};

// Then in your D class, change the call from `foo` to `bar`

template <class T>
class D : public B<T>
{
protected:
    void foo() override
    {
        B<T> *b = new C<T>();
        b->bar();
    }
};

Это может не соответствовать вашему конкретному сценарию, но в итоге ваша проблема сводится к необходимости доступа public.

Надеюсь, что это поможет.

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