To begin with, I know about C++ Standard (ISO/IEC 14882:2003): Section 11.5, Paragraph 1, and this is not that case (but compliler apparently does not think so).
I try to call protected base class method in derived class method through this pointer, static-casted to base class pointer and have in MSVC2008 error C2248: 'A::f' : cannot access protected member declared in class 'A'.
I have to do this in context of 'curiously recurring template pattern', but I can reproduce this error in simplier code, as follows:
class B
{
protected:
void f(){}
};
class D : public B
{
public:
void g()
{
f(); // ok
this->f(); // ok
static_cast<B*>(this)->f(); // C2248 in MSVC2008
dynamic_cast<B*>(this)->f(); // C2248
((B*)this)->f(); // C2248
}
};
D d; d.g();
It seems that compiler think of casted this pointer as a pointer to other instance, yeah?
The compiler is wrong in this case, what do you think?
Ok, my real code is more like that:
template<class T>
class B
{
public:
void g()
{
f(); // error C3861: 'f': identifier not found
this->f(); // error C3861: 'f': identifier not found
// static_cast to derived class
static_cast<T*>(this)->f(); // C2248 in MSVC2008
}
};
class D : public B<D>
{
protected:
void f(){}
};
I cast this to derived class, and I can't use this->f();
By the way, I see that this code is unsafe for usage like class E : public B<D> {...};
: compilable, but static_cast makes wrong cast.
When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class's version of the function.
Explanation: A base class pointer can point to a derived class object, but we can only access base class member or virtual functions using the base class pointer because object slicing happens when a derived class object is assigned to a base class object.
Derived class pointer cannot point to base class.
Protected members in a class are similar to private members as they cannot be accessed from outside the class. But they can be accessed by derived classes or child classes while private members cannot.
The compiler is correct. To explicitly access the B::f
member function, you can write:
this->B::f();
The relevant language is:
c++11
11.4 Protected member access [class.protected]
[...] Access to a protected member is granted because the reference occurs in a friend or member of some class C. [...] Access to a protected member [...] involve[s] a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall be C or a class derived from C.
Thus protected member access via a cast to the base class B
violates this grant, and is disallowed. It is also unnecessary for the reason that you can use this->B::f()
as above.
In the case with your actual CRTP motivation, you are correct that you cannot call f()
without a static_cast
, since D
is not a base class of B<D>
(the inheritance relationship is in the other direction). Since D
is not a base class of B<D>
, you cannot call its protected
methods from B<D>
anyway. One simple workaround is to friend
B<D>
to D
and use the static_cast
on the this
pointer:
template<typename T>
class B {
public:
void g() {
static_cast<T *>(this)->f();
}
};
class D : public B<D>
{
friend class B<D>;
...
If giving B
access to the private
parts of D
worries you, you can move the private
parts to another base class and isolate the CRTP mechanism in D
:
template<class T> class B {
public:
void g() {
static_cast<T*>(this)->f();
}
};
class C {
private:
void h();
protected:
void f(){ std::cout << "D::f\n"; }
};
class D: protected C, public B<D>
{
friend class B<D>;
};
Here B<D>
is prevented from calling C::h
as friendship is neither inherited nor transitive.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With