|  | protected vs static members |  | |
| | | spambouncer@gmx.de |  |
| Posted: Thu Aug 28, 2008 8:53 pm Post subject: protected vs static members |  |
| |  | |
Hi group!
A static function in a derived class can't access a protected data member from the base class, although class access is public:
class A { protected: static void f(A* instance) { ++(instance->d_); } int d_; };
class B : public A { protected: void g() { --d_; // sanity check: accessing protected member from non- static function is fine } static void f(A* instance) { --(instance->d_); // error: 'A::d_' : cannot access protected member declared in class 'A' } };
However, if the instance pointer is changed to point to the derived class, everything is fine:
class B : public A { protected: static void f(B* instance) { // points to an instance of B now --(instance->d_); // fine } };
Just out of curiosity, what's going on here? I got a hunch that accessing A->d_ from B::f() is like accessing d_ from outside the class, which is not allowed because d_ is protected. But why would A* be considered a pointer to an arbitrary class, when the compiler knows that B is derived from A and has access to its protected members? Could someone clear that up, please?
Thanks, Andreas.
-- [ See LINK for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
| |
| | | Chris Uzdavinis |  |
| Posted: Fri Aug 29, 2008 6:37 am Post subject: Re: protected vs static members |  |
| |  | |
On Aug 28, 4:53 pm, "spamboun...@gmx.de" <spamboun...@gmx.de> wrote:
| Quote: | Hi group!
A static function in a derived class can't access a protected data member from the base class, although class access is public .... However, if the instance pointer is changed to point to the derived class, everything is fine: .... Just out of curiosity, what's going on here? I got a hunch that accessing A->d_ from B::f() is like accessing d_ from outside the class, which is not allowed because d_ is protected. But why would A* be considered a pointer to an arbitrary class, when the compiler knows that B is derived from A and has access to its protected members? Could someone clear that up, please?
|
The part you're overlooking is that protected access is limited inside a derived class to only grant access to other objects of the same (derived) type. If you were allowed to do what you are trying to do, then if you had multiple classes sharing a common base, they would be allowed to edit each other's protected data, which violates the promise that only the derived class can access.
Given an arbitrary pointer to the base type, there is no way to know at compile time the dynamic type of the "pointed-to" object, and so there is no way to know whether access should be granted, so it's not.
For a concrete example:
class base { protected: int data; };
class derived1 : public base {};
class derived2 : public base { public: void f(base * b) { b->data = 999; // not allowed } };
int main() { derived1 d1; derived2 d2;
d2.f(&d1); }
If derived2::f() were allowed to edit b->data directly, then it could access the data in other derived types. Objects of type derived1 are only allowed access to derived1::data, and objects of type derived2 are only allowed access to derived2::data.
-- Chris
-- [ See LINK for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
| |
| | | Alf P. Steinbach |  |
| Posted: Sat Aug 30, 2008 2:48 pm Post subject: Re: protected vs static members |  |
| |  | |
* spambouncer@gmx.de:
| Quote: | A static function in a derived class can't access a protected data member from the base class, although class access is public:
|
You mean, a particular static function.
The fact that it's static is irrelevant here.
| Quote: | class A { protected: static void f(A* instance) { ++(instance->d_); } int d_; };
class B : public A { protected: void g() { --d_; // sanity check: accessing protected member from non- // static function is fine } static void f(A* instance) { --(instance->d_); // error: 'A::d_' : cannot access // protected member declared in class 'A' } };
|
It has nothing to do with static versus non-static, but all to do with ensuring the stated access level, 'protected'.
To make the non-static member function B::g comparable to B::f, you would have to change B::g to be a copy of B::f without the 'static' keyword. Then you'd get the same error. As it is you're comparing apples with oranges.
| Quote: | However, if the instance pointer is changed to point to the derived class, everything is fine:
class B : public A { protected: static void f(B* instance) { // points to an instance of B now --(instance->d_); // fine } };
Just out of curiosity, what's going on here?
|
Here you've changed B::f to essentially be a copy of B::g, just with 'static' added, and the situation is the same, no error.
| Quote: | I got a hunch that accessing A->d_ from B::f() is like accessing d_ from outside the class, which is not allowed because d_ is protected.
|
No, the last example illustrates that it matters very much that it's a member function. If you'd made the last example's B::f a free-standing function it wouldn't have compiled. The 'static' or not does not matter, but class membership does.
| Quote: | But why would A* be considered a pointer to an arbitrary class, when the compiler knows that B is derived from A and has access to its protected members? Could someone clear that up, please?
|
There is a class A, very much like your class A, with a protected data member. There's also a class Target derived from A, written by someone else. Me, the novice hacker, I'm very much interested in accessing the d_ member of a Target instance directly (which may break assumptions of class Target, but I'm doing this to shave off a nano-second), and to do that I ingeniously derive from A:
<code> #include <iostream>
class A { protected: int d_;
public: A(): d_(42) {} int d() const { return d_; } };
class Target: public A {};
class TargetHack: public A { public: static void setD( A& a ) { a.d_ = 666; } };
int main() { Target o; TargetHack::setD( o ); std::cout << o.d() << std::endl; } </code>
This does not compile. And the reason it doesn't compile is that the C++ access rules are designed to not let me hack into a class that easily. There is of course nothing preventing me from using casts or preprocessor stuff or other such things to gain entrance, perhaps with some damage, but the door is not open: I can't get in there by *accident*, the 'protected' *does* have an effect.
Well, except for...
Type system loophole. If you use member pointers you *can* gain entrance by accident. In the simple, clear example code below this would not be by accident, but in somewhat more complex code the same could conceivably happen by accident. So this is worth keeping in mind: member pointers are not type safe. They're very very un-typesafe. Think of them as simple offsets, where it's you who are telling the compiler what actual type that object is, i.e., that copying a member pointer essentially involves an *implicit cast* (to be pedantic, a cast is a syntactic thing whereas here it's all about type conversion, but), which cast in effect transfers the accessibility up to a class where it shouldn't be.
Put another way, while macros don't respect scopes, member pointers don't respect accessibility.
So member pointers are sort of at the level of macros, but with the problem that they might seem to be type safe, which they're not.
<code> #include <iostream>
class A { protected: int d_;
public: A(): d_(42) {} int d() const { return d_; } };
class Target: public A {};
class TargetHack: public A { public: static void setD( A& a ) { int A::*p = &TargetHack::d_; a.*p = 666; } };
int main() { Target o; TargetHack::setD( o ); std::cout << o.d() << std::endl; } </code>
Compared to the H-bomb effect of implicit conversion from array to pointer this type system hole is almost like a little firecracker, just fun, amusement for tired C++ programmers. But, if a firecracker goes off at the wrong time and place, it can do very much damage. So, it's a generally a good idea to avoid direct use of member pointers, just as with avoiding direct use of raw pointers in general, and avoiding goto in general, and other direct use of lowest levels.
I guess one could spark off a little heated debate by asserting that hey, it's not the fault of member pointers, it's the use of 'protected' data!
So, herewith ), but since my articles generally have a much higher lag time for acceptance than others', I probably won't be able to participate.
Cheers & hth.,
- Alf
-- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail?
[ See LINK for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
| |
|
|