Рассмотрим следующий код:
#include <iostream>
using std::endl;
using std::cout;
template<typename T>
class B{
protected:
T value;
B* ptr;
public:
B(T t):value(t), ptr(0){}
};
template<typename T>
class D: public B<T>{
public:
void f();
D(T t):B<T>(t){}
};
template<typename T>
void D<T>::f(){
cout << this->value << endl; //OK!
this->ptr = this;
cout << this->ptr->value << endl; //error! cannot access protected member!!
B<T>* a = this;
cout << a->value <<endl; //error! cannot access protected member!!
}int main(){
D<double> a(1.2);
a.f();
return 0;
}
Кажется, что к члену базового класса можно напрямую получить доступ, используя this
указатель, но не другие указатели.
Считает ли компилятор их различными экземплярами?
Да, это ожидаемое поведение. Защищенные участники базового класса можно получить в производном классе, но только через объект типа, который является производный класс (или дополнительный производный класс текущего производного класса) (включая this
). Это означает, что вы не можете получить доступ к защищенным членам через указатель на базовый класс.
Доступ к защищенному члену класса Base возможен только
1) …
2) членами любого класса, производного от Base, но только когда
работающий с объектом типа, который является производным от Base (включая
этот)
Более простой пример теста:
class Base
{
protected:
int i;
};
class D1 : public Base
{
};
class D2 : public Base
{
int a(Base& b) { return b.i; } // error
int a(D1& d) { return d.i; } // error
int a(D2& d) { return d.i; }
};
В производном классе D2
мы можем получить доступ Base::i
в D2
экземпляр, но не в Base
экземпляр, ни в объекте, который является производным от Base
не через D2
,
В остальном хороший [C ++ Reference] [защищенный] говорит:
Защищенный член класса
Base
могут быть доступны […] членам любого класса, полученного изBase
, но только при работе с объектом типа, который является производным отBase
(в том числеthis
).
Приведенный выше тест предполагает, что формулировка там немного неточна — она должна читаться «только при работе с объектом своего собственного типа или объекта, производного от него».
¹ или что GCC неверен — мы должны действительно проверить стандарт для этого.