NOTE: This question is written in a C# like pseudo code, but I am really going to ask which languages have a solution. Please don’t get hung up on syntax.
Say I have two classes:
class AngleLabel: CustomLabel
{
public bool Bold; // Just upping the visibility to public
// code to allow the label to be on an angle
}
class Label: CustomLabel
{
public bool Bold; // Just upping the visibility to public
// Code for a normal label
// Maybe has code not in an AngleLabel (align for example).
}
They both decend from this class:
class CustomLabel
{
protected bool Bold;
}
The bold field is exposed as public in the descended classes.
No interfaces are available on the classes.
Now, I have a method that I want to beable to pass in a CustomLabel and set the Bold property. Can this be done without having to 1) find out what the real class of the object is and 2) cast to that object and then 3) make seperate code for each variable of each label type to set bold. Kind of like this:
public void SetBold(customLabel: CustomLabel)
{
AngleLabel angleLabel;
NormalLabel normalLabel;
if (angleLabel is AngleLabel )
{
angleLabel= customLabel as AngleLabel
angleLabel.Bold = true;
}
if (label is Label)
{
normalLabel = customLabel as Label
normalLabel .Bold = true;
}
}
It would be nice to maybe make one cast and and then set bold on one variable.
What I was musing about was to make a fourth class that just exposes the bold variable and cast my custom label to that class.
Would that work?
If so, which languages would it work for? (This example is drawn from an old version of Delphi (Delphi 5)). I don’t know if it would work for that language, (I still need to try it out) but I am curious if it would work for C++, C# or Java.
If not, any ideas on what would work? (Remember no interfaces are provided and I can not modify the classes.)
Any one have a guess?
It would work in Delphi. Code in the same unit as the classes it uses have implicit access to protected (but not strict protected) members, even those members declared in another unit. You’de declare the property protected in
CustomLabel:The bold-setting procedure, in another unit, would have its own
CustomLabeldescendant:You can’t use an
ascast on that because the actual parameter will never be an instance ofTAccessLabel. It will be an instance ofAngleLabelorNormalLabel, but since the portions inherited fromCustomLabelby all three classes are common, theBoldproperty is the same in all of them. That remains true even after the property has been publicized or published in a descendant:You can change the visibility of properties, but not fields. If you try the same thing with a field, you’ll be declaring a new field with the same name that hides the inherited field.
You can do something similar in C++, but it’s not as commonly done as it is in Delphi, so it’s likely to draw some ire, especially if you intend to write portable code.
Declare a fourth class, like in Delphi. C++ isn’t as loose with member access as Delphi is, but it has the concept of friendship, which works just as well in this case.
That function now has full access to the class’s members:
That’s technically undefined behavior because we’ve type-casted an object to a type that it doesn’t really have. We’re relying on all descendants of
CustomLabelto have the same layout, in particular for theboldmember of anAccessCustomLabelto reside at the same relative position as theboldmember of any otherCustomLabeldescendant.The type casting in the Delphi and C++ code performs type punning. You’re not going to get away with that in C# or Java; they check the results of their casts, so if
customLabeldoesn’t really hold an instance ofAccessCustomLabel, you’ll get an exception. You’ll have to use reflection to access the protected members of unrelated classes in those languages. Demonstrating that is beyond my depth.