|
The following doesn't compile:
struct A
{
A* partner;
void doodah()
{ ++partner->value; } //this is legal
protected:
int value;
};
struct B: public A
{
void foobar()
{ partner->value += 2; } //but this isn’t
};
The complaint is that foobar() can't access A::value. But B is an A and A can access the value member of another A. So why can't B - which IS AN A - access the value member of another A?
--Dave Schumann
|
|
|
|
|
i really don't see anything wrong in the code (except the doodah() method is a little dirty, but anyway).
what does the compiler say exactly (code + message) ?
TOXCCT >>> GEII power
[VisualCalc 3.0 updated ][Flags Beginner's Guide new! ]
|
|
|
|
|
FILENAME.cpp(230) : error C2248: 'A::value' : cannot access protected member declared in class 'A'
FILENAME.cpp(224) : see declaration of 'A::value'
FILENAME.cpp(218) : see declaration of 'A'
line 230 is the "partner->value += 2" call in foobar(). It has no complaint about the "++partner->value" call in doodah().
I'm not a language lawyer but this seems like it should be legal.
|
|
|
|
|
It may be that you are trying to implement class like behaviour using structs.
Try this:
struct A
{
// Let the compiler know that B can access A's protected members.
friend struct B;
A* partner;
void doodah()
{ ++partner->value; } //this is legal
protected:
int value;
};
Dave Kerr
codechamber@hotmail.com
http://www.codechamber.com
|
|
|
|
|
But a class *is* a struct.
Christian Graus - Microsoft MVP - C++
Metal Musings - Rex and my new metal blog
|
|
|
|
|
Christian Graus wrote: But a class *is* a struct.
hum, yes, but i would have said here that a struct *is* a class
only a matter of point of view
TOXCCT >>> GEII power
[VisualCalc 3.0 updated ][Flags Beginner's Guide new! ]
|
|
|
|
|
Internally yes a class is a struct with a vftbl.
Regardless, this does solve the problem. Changing the structs to classes does not, neither does explicitly declaring partner as public.
More explicit casting :
void foobar()
{ ((::A*)this)->partner->value += 2; }
or
void foobar()
{ ((A*)this)->partner->value += 2; }
as mentioned in the notes for Compiler Error C2248 on MSDN doesn't work either. It's rather an odd one.
Dave Kerr
codechamber@hotmail.com
http://www.codechamber.com
|
|
|
|
|
Oh - casting this to an A*. That seems like a really good idea. Pity it doesn't work but it would have made sense if it did .
Yeah I'm confused too. I hope a language lawyer blunders onto this post...I'm wondering whether this is a standards violation or not.
|
|
|
|
|
A "struct" is a class with default public protection. You can change it to a class, put a "public:" at the beginning, and have the same result.
And although in this toy example I could get it to compile with a "friend struct B" declaration, that's stupid. B is a CHILD CLASS. Why should I have to declare it a friend? Why should I even have to know about it? My child classes are supposed to be able to access my protected members.
|
|
|
|
|
my first thought was that A* partner; in A is in the private section of the class, so it is not accessible to B, but you're dealing with struct, and all members in structs should be public; so I'm a little bit confused.
Maximilien Lincourt
Your Head A Splode - Strong Bad
|
|
|
|
|
Dave Schumann wrote: So why can't B - which IS AN A - access the value member of another A?
It's a difference in the way structs differ from classes. If you remove A::value from the protected section, it'll compile.
"The largest fire starts but with the smallest spark." - David Crow
"Judge not by the eye but by the heart." - Native American Proverb
|
|
|
|
|
Maximilien wrote: all members in structs should be public
no. this is true only is you don't redefine the visibility (which is actually done here with protected: )
TOXCCT >>> GEII power
[VisualCalc 3.0 updated ][Flags Beginner's Guide new! ]
|
|
|
|
|
>>>It's a difference in the way structs differ from classes
No it's not. Changing these to "classes" with public: at the beginning has no effect (I've tried it)
|
|
|
|
|
Dave Schumann wrote: No it's not.
Sure it is.
Dave Schumann wrote: Changing these to "classes" with public: at the beginning has no effect (I've tried it)
It won't have an effect until you put A::value into a public section. This is the default with a struct . So, you'll either need:
struct A
{
A* partner;
void doodah()
{ ++partner->value; }
int value;
}; or
class A
{
public:
A* partner;
void doodah()
{ ++partner->value; }
int value;
};
"The largest fire starts but with the smallest spark." - David Crow
"Judge not by the eye but by the heart." - Native American Proverb
|
|
|
|
|
>>>Sure it is.
No - it's not. You said it has something to do with struct vs. class - it doesn't. Change them to clases with public scope at the beginning and everything will be the same. What you did was remove the "protected:" which has nothing to do with it being a struct or not.
I declared "protected:" for a reason, not because I like having things not compile. This is a toy version of a much larger problem. I can't stand posters who post 20 pages of code so I figured I'd boil the issue down. In fact in my case the issue is accessing a *function*...and there's virtual stuff and blah blah blah. Now you're getting bored, appropriately. None of that is relevant to the compiler error which I can't understand.
|
|
|
|
|
Dave Schumann wrote: I declared "protected:" for a reason, not because I like having things not compile. This is a toy version of a much larger problem. I can't stand posters who post 20 pages of code so I figured I'd boil the issue down. In fact in my case the issue is accessing a *function*...and there's virtual stuff and blah blah blah. Now you're getting bored, appropriately. None of that is relevant to the compiler error which I can't understand.
Since you aren't giving the details of your larger problem (understandably), I will only mention that almost always, protected should be replaced by private. See Effective C++ by Scott Meyers for details.
If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week
Zac
|
|
|
|
|
Zac Howland wrote: I will only mention that almost always, protected should be replaced by private.
maybe, but here, the protected member is accessed by a children... so, putting it private will cause a new problem in his code.
TOXCCT >>> GEII power
[VisualCalc 3.0 updated ][Flags Beginner's Guide new! ]
|
|
|
|
|
toxcct wrote: maybe, but here, the protected member is accessed by a children... so, putting it private will cause a new problem in his code.
That hits to the design issue I was referring to.
If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week
Zac
|
|
|
|
|
So would it be permissible to just add a "getter" method to A ?
"The largest fire starts but with the smallest spark." - David Crow
"Judge not by the eye but by the heart." - Native American Proverb
|
|
|
|
|
Yes, me too. It's not complaining about accessing "partner" - it's complaining about accessing "partner::value" even though B is a child of A and "value" is a protected member.
This is a toy version of a real problem I'm having (I trusted that the "A", "B", "foobar", and "doodah" names would make that relatively obvious ). My real problem involves much larger *classes* (not structs...again this is a toy problem) and the real-life version of "A" is not easy to modify. I was honestly shocked I was able to write this toy version that doesn't compile (it really doesn't - just cut'n'paste and see for yourself). I assumed that the problem was some complicated thing about my larger classes and their relationships or whatever...but no, it's really not letting me do this.
|
|
|
|
|
Dave Schumann wrote: It's not complaining about accessing "partner"
And it won't. partner has public access. If it complained about that, I would be really shocked.
This link may help you as well: C++ Protection
If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week
Zac
|
|
|
|
|
Yeah - I found the relevant portion of the standard. It actually specifies an EXTRA CHECK for cases like this. Why?? See "solution" below for section and quote.
|
|
|
|
|
I believe the reason why is that you could completely circumvent protection by using inheritence if they did not do this check.
If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week
Zac
|
|
|
|
|
well you can basically "completely circumvent" protection anyway. For example:
LIBRARY:
class A
{
protected:
int value;
};
MY CODE:
//now let's say I want to access value in an 'A' object I have. I just write this:
class A_breaker: public A
{
public:
int* accessValue()
{ return &value; }
};
void my_function (A& my_a)
{
int* value_ptr = ((A_breaker&)my_a).accessValue();
//now I can do anything
}
...so if they were trying to make "protected" bulletproof, they didn't succeed at all. (I've actually compiled the above and it's perfectly legal...and, incidentally, the cast to A_breaker is perfectly safe since A_breaker adds no data)
-- modified at 13:01 Wednesday 12th July, 2006
|
|
|
|
|
I doubt they were trying to make it bulletproof. Chances are they were trying to provide as strict a mechanism for it as possible while still allowing for old C-Style code to compile.
If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week
Zac
|
|
|
|