JAM said:
Knows in a sense that since B is derieved from A my guess was that it
should see protected members of A even if A is not the base instance
of B. Obviously I was wrong, but I don't fully understand the reason
for this restriction.
Okay…maybe I wasn't careful enough in my previous explanation. I'll try
again…
When I construct B derieved from A I expect B to
see protected members of it's base class.
I would like you to try to consider why class A has protected members in
the first place, rather than just private and public, and given that why
class B should have access to protected members in class A.
Here's _my_ answer to that: the protected members are there to support
inheritance that allows the derived class to manipulate or otherwise use
those members. You can't allow that access for private members, because
then you can't design classes that have implementation details that are
hidden even from derived classes. And obviously you don't want those
details to be public, because that's implementation, not interface.
So we have protected. But it's there to support inheritance. As such,
they should be visible only to the class that has inherited them. So,
code in class B does have access to protected members. But only in
instances of class B, because that's the only class that should have
access to _any_ hidden members of class B.
If that doesn't seem to help explain it, consider this: the usage of a
protected member is defined by the class in which its contained. Once
class B is permitted to inherit a protected member, it gets to impose
its own usage rules on the protected members.
But, class B does not have any specific knowledge regarding how any
other class might use that member.
For example:
class Temperature
{
public int Value
{
get { return _temp; }
set { _temp = value; }
}
protected int _temp;
}
class Fahrenheit : Temperature
{
public int Celsius { get { return (_temp - 32) * 5 / 9; } }
}
class Celsius : Temperature
{
public int Fahrenheit { get { return _temp * 9 / 5 + 32; } }
}
Now, ignoring for a moment that classes designed like that are probably
not a good idea for other reasons, how is the Celsius class supposed to
successfully use the variable _temp found in instances of Temperature
that are not known to be also instances of Celsius?
What makes it so different
if instance of A is not a base for particular B ? The author of class
A by making function "protected" already assumed that author of B will
eventually be allowed to use it and in order to use it must assume
responsibility for using it properly.
But only in the context of the inheriting class.
Frankly, I think protected members should be generally avoided, and this
is ten times more true IMHO for variables. Even between base and
derived classes, hiding implementation is a very good thing.
But, inasmuch as there may be a need to share implementation between the
base class and the derived class, there's no way to ensure in the design
of the code that when one derived class accesses a protected member that
is actually a member of a completely different derived class, that it's
doing so in a way that is consistent with the first derived class's
understanding of the member.
Thus, that's simply not allowed.
I think you are too judgmental.
People who receive criticisms that they are unprepared to hear often
think that. Sorry about that. I do not intend to be judgmental, except
with respect to judging the _code_ and its design. Please don't take it
personally.
This is not as "unusual" as you suggest.
I have enough experience in the area for me to confidently say that it is.
Windows file system is a good example of such tree.
It's not, actually. Not in the sense that it supports the design you
seem to be working with.
The root
node is a disk drvie whereas nodes of the tree are directories.
Okay, let's take that abstraction as granted. We still cannot conclude
that there's any good reason for a node of one type to access a
protected member found in a node of another type.
Why should a node representing a drive have access to otherwise-private
members in a node not representing a drive? Or vice a versa? If that
member is protected, it's because the derived class is expected to do
something special with it. Something special that is not shared in
common with every class that inherits the base class.
If the derived class is not doing anything special with the protected
member, then that means the member should not have been marked as
protected in the first place. It should have been private, with all of
the general-purpose implementation in the base class.
Or, looking at your example from a slightly different point of view: as
far as the _tree_ structure is concerned, the shared base class that
describes the tree is the only important thing. Any code related to the
management of the tree itself should not care whether the node
represents a drive or a directory within a drive. And inasmuch as any
code is specific to one type of node or the other, that code should
operate only on the type of node in which that code exists.
[...]
My tree is similar to the one mentioned for Windows Explorer. It has
root node that has some of the functionality of subnodes but also has
much more additional functionality and stores additional information
It is always predefined to reside as the root. Every other node in the
tree is of the other class type and does not need extended
functionality or storage. It seemed usefull to make B root node and A
other nodes where B : A.
Been there, done that, and having done that I know for sure you don't
need a design in which a protected member is accessible from without the
class actually inheriting that member.
Pete