Ваша проблема не имеет ничего общего с шаблонами и выдает ту же ошибку, если вы удаляете весь шаблонный код.
Объявление элемента как 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
.
Надеюсь, что это поможет.