From: Peter Duniho on 1 Feb 2010 14:19 JAM wrote: > On Jan 31, 10:36 pm, Peter Duniho <no.peted.s...(a)no.nwlink.spam.com> > wrote: >> That's correct. To access a protected member of a base class, your >> class has to access that protected member via a variable of its own type. >> >> Consider the alternative: if you could start accessing protected members >> of _any_ instance of a class A just by inheriting A and doing it from >> the sub-class, then accessibility protection would be basically >> meaningless. You could bypass it anytime you want just by inheriting >> the class you want to get at. > > Sure, but I would do it on purpose so the assumption would be that I > know what I'm doing. I don't see the alternative as being so bad here. OOP encapsulation rules are predicated on the assumption that any code other than the code in the class is not written by someone who "knows what they're doing". If you would prefer to work without the constraints that these language rules provide, you probably would prefer to work in a different language. Alternatively, if you insist that you always "know what you're doing", why not just make everything in the class public. Then you have complete access, and don't have to worry about the compiler looking over your shoulder every time you want to do something. :) Not something I'd advise personally. But you can do it that way if you find the rules too constraining. >> Note that if your "items" variable was a "List<B>", the access would >> have been just fine. That's because the class B is trusted to access >> protected members in instances of itself. > > But that actually would make my program less self explanatory. Uh, not really. Not within the constraints of the C# language. > In my > program class A is a node in the tree structure. > Class B is a root node of that tree. B requires slightly different > handling than A, that is why it is derived from A. > The list is a list of subnodes. It would make akward reading if the > list would be a list of rootnodes. If you can't guarantee that the elements in the list are of type B, then IMHO your code has no business accessing protected members of the instances in the list from code in class B. If you _could_ guarantee the elements are of type B (sounds like you can't, but speaking hypothetically), then of course using type B in the list is more "self-explanatory". > Function F in my program simply > opens particular branch (recursively) from data file. However root > node cannot use F to open itself. It uses different function. But then > it opens it's entire branch using F for all it's subnodes from the > list. There is no reason for F to be used anywhere else. That is why I > tought it would be a good idea to hide it from public interface. It's hard to speak of specifics without specific code. But having written various tree-based UIs myself, including those linked to data files and to file system structures, I can safely say that having your tree made up of different kinds of nodes depending on their location within the tree is a highly unusual, and highly suspect, design. This is in fact consistent with my more general observation I mentioned before: if you find yourself fighting the language, you've probably made a design error somewhere. This might be the design error you've made: having two different node types in the same tree, at least as far as the tree itself is concerned (of course, one can imagine a tree structure with varying node types, but they would all inherit the same base class, and the code dealing with the tree would only care about that base class, not all the various sub-class types). > [...] >>> Do I have to expose F as public to be able to access it when >>> particular A is not a base for this particular B but when the A >>> belongs somehow to this particular B which has some different A as >>> base ? >> That sentence is pretty awkward. > > Sorry. English is not my first language. Well, then your sentence is surprisingly well constructed. :) (Seriously, I never would have guessed English isn't your first language, so you're doing way better than many native speakers of English :) ). > [...] >> But as a general rule, yes�if you have a member in one class that you >> want to be accessible via code not in an instance of the class in which >> the member is defined, that member has to be public. > > Well, then I think my particular case proves that C# in rare > situations is lacking more granular access control that would be > usefull. Personally, I think your particular case proves that you could improve your design. :) >> I would furthermore argue that if you find yourself trying to design a >> class to the contrary of this, that you've made a mistake in the program >> design. > > What you think about my example ? In my experinece with tree > structures it often happens that root node has slightly different > needs that other nodes. I've written hundreds of tree structures in my career, and have never had to have a root node be a different type or handled differently than the other nodes. I would be happy to try to offer more specific advice if you can provide more details of your problem. But I do believe that you can solve your problem quite well and elegantly without violating C#'s access rules, and even without using "internal" as your access modifier. Pete
From: JAM on 1 Feb 2010 15:45 On Feb 1, 2:19 pm, Peter Duniho <no.peted.s...(a)no.nwlink.spam.com> wrote: > OOP encapsulation rules are predicated on the assumption that any code > other than the code in the class is not written by someone who "knows > what they're doing". 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. When I construct B derieved from A I expect B to see protected members of it's base class. 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. > It's hard to speak of specifics without specific code. But having > written various tree-based UIs myself, including those linked to data > files and to file system structures, I can safely say that having your > tree made up of different kinds of nodes depending on their location > within the tree is a highly unusual, and highly suspect, design. I think you are too judgmental. This is not as "unusual" as you suggest. Windows file system is a good example of such tree. The root node is a disk drvie whereas nodes of the tree are directories. I do realize that in fact behind "disk drive" is really root directory of the drive, but still it makes easier to consider root node as different from others. There is substantial amount of functionality that applies to disk drive but is not applicable to some directory on that drive. Windows 7 added Libraries, which probably need another node type to distinguish them from conventional directory so one can imagine even more rich tree. Windows Explorer also introduces node callled "MyComputer" - the very top node of the entire tree which is neither a disk drive nor directory and none of typical directory or disk functions apply to it. > I would be happy to try to offer more specific advice if you can provide > more details of your problem. But I do believe that you can solve your > problem quite well and elegantly without violating C#'s access rules, > and even without using "internal" as your access modifier. 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. > > Pete
From: Peter Duniho on 1 Feb 2010 18:39 JAM wrote: > On Feb 1, 2:19 pm, Peter Duniho <no.peted.s...(a)no.nwlink.spam.com> > wrote: > >> OOP encapsulation rules are predicated on the assumption that any code >> other than the code in the class is not written by someone who "knows >> what they're doing". > > 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. >> It's hard to speak of specifics without specific code. But having >> written various tree-based UIs myself, including those linked to data >> files and to file system structures, I can safely say that having your >> tree made up of different kinds of nodes depending on their location >> within the tree is a highly unusual, and highly suspect, design. > > 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
From: JAM on 1 Feb 2010 21:49 On Feb 1, 6:39 pm, Peter Duniho <no.peted.s...(a)no.nwlink.spam.com> wrote: > JAM wrote: > ... > 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. This is what I don't fully get. I don't see the difference between base instance and some other instance. If I can abuse protected member of A when A is not base instance of B, then I can certainly make the same abuse by incorrectly using protected member of A in B when A is a base instance of B. > 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? Well. Consider the opposite. If you have instance of Celsius, how usage of base._temp makes it any different ? If author of Celsius has no idea, of what exactly _temp does and how is used in Temperature, why would author of B be any safer of using _temp in valid code case when he is accessing it from the instance of B ? Also consider, that in my problem I was not attempting to use protected member of class A but I was attempting to execute protected member of the instance of class A from within class B. The only difference was, that that instance of A was not a base instance of calling B. From the purity standpoint I can see your point that protected just works this way as designed (which I did not know) and possibly has some value. However my point is, that I see a value in my approach too however rare. Maybe some other that public, protected or private modifier would be needed to clarify this different approach. > 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. I agree but there are times when it is the simplest approach. My problem is, that I was forced to use public in A. In my opinion I ended up with more polluted code. Now the damn function is visible to every class and it was only needed to be visible in B > 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. You proof is circular. If there is no reason to access protected member the member would be private. If the member if protected, there must be a value in accessing it from class that inherits. And since class that inherits can access it, it must do it correctly or the code will produce garbage whether accessed class is a base instance or not. The whole discussion is about value of accessing protected member. At least one value is that when I use code completion, protected functions will not show up in the list so I can't use them by laziness. By forcing me to make function in A public in my specific case, now I see the damn function every time I code something for A or B and that was not my intent. > 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. With all do respect I agree to disagree here. > > Pete JAM
From: Family Tree Mike on 1 Feb 2010 22:29 JAM, So take the following classes: class A { protected void F() {} } class B : A { public List<A> items; public void B() { items[0].F(); // <-- This does not generate an error } } class C { public List<A> items; public void C() { items[0].F(); // <-- This generates an error } } You view the line in class B is acceptable only because the instance of A (items [0]) is accessed from a subclass of A? But you also feel that in class C, this would be illegal as C is not subclassing A, even though it (items [0]) is still an instance of an A? I'd hate to think about diagnosing that code later, among other nightmares... -- Mike
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 4 Prev: Globalized propertyGrid description Next: Sort Error in Crystal Report Code with VS 2005 |