Reputation: 2714
In C#, we can not change access modifier while overriding a method from base class. e.g.
Class Base
{
**protected** string foo()
{
return "Base";
}
}
Class Derived : Base
{
**public** override string foo()
{
return "Derived";
}
}
This is not valid in C#, It will give compile time error.
I want to know the reason, why it's not allowed. Is there any technical problem or can it lead to something which is not consistent in terms of access restriction???
Upvotes: 51
Views: 32619
Reputation: 51
Here is my understanding:
There are two things to keep in mind while inheriting a class.
When trying to decide whether to inherit a class, consider these two things independently.
If you want only the functionality being exposed by the class's member methods, a better way would be to use composition instead of inheritance. That way, you can define the API / contract of your class and keep whatever members, methods you want as public, private or protected.
If you want that your class should conform to the API of the class you are trying to inherit as well, then go for inheriting the class. When you are inheriting a class, you are essentially agreeing that the class you are creating does not break the API guaranteed by the base class since your class IS ALSO A parent class type. Part of guaranteeing that the base class's API is not broken is to not change the access specifiers.
Upvotes: 0
Reputation: 379
Overriding is a term which enables you to change or augment the behavior of methods in a base class. Overriding gives you the control to write new logic for an existing method.
Changing the method signature of a base class is somewhat like writing a new method instead of overriding the existing one. It contradicts the purpose of overriding a method. So maybe the reason why you cannot change the access modifier while overriding methods in C#.
Upvotes: 0
Reputation: 8306
Reducing visibility is impossible because if Base.Member
was visible and Derived.Member
was not visible, that would break the whole “Derived
is a Base
” concept in OOP. However, increasing visibility is disallowed maybe because the language developers think that changing the visibility would be a mistake most of the time. However, you can always use the new
keyword to hide base class members by introducing a member with the same name but a different behavior. This new member belongs to the derived type’s interface, so of course you can still access the base type’s interface by casting to that base type. Depending on how you write your subclass, your new
member might effectively increase the visibility of the base class’s property—but remember that the base class’s property can still be accessed directly (e.g., a subclass of your subclass could cast this
to Base
and bypass your property).
The question here is how to both override
and new
the same named member (identifier) in a subclass. That is apparently not possible. At the very least, I can say through experimentation that public new override string foo(){return "";}
is not a syntax for that. However, you can get the same effect by using two subclasses:
using System;
class Base
{
protected virtual string foo()
{
return "Base";
}
public void ExhibitSubclassDependentBehavior()
{
Console.WriteLine("Hi, I am {0} and {1}.", GetType(), foo());
}
}
abstract class AbstractDerived : Base
{
protected virtual string AbstractFoo()
{
return base.foo();
}
protected override string foo()
{
return AbstractFoo();
}
}
class Derived : AbstractDerived
{
protected override string AbstractFoo()
{
return "Deprived";
}
public new string foo()
{
return AbstractFoo();
}
}
static class Program
{
public static void Main(string[] args)
{
var b = new Base();
var d = new Derived();
Base derivedAsBase = d;
Console.Write(nameof(b) + " -> "); b.ExhibitSubclassDependentBehavior(); // "b -> Hi, I am Base and Base."
Console.WriteLine(nameof(d) + " -> " + d.foo()); // "d -> Deprived"
Console.Write(nameof(derivedAsBase) + " -> "); derivedAsBase.ExhibitSubclassDependentBehavior(); // "derivedAsBase -> Hi, I am Derived and Deprived."
}
}
The intermediate subclass (AbstractDerived
) uses override
and introduces a new, differently-named member that the subclass and sub-subclasses can continue to override
the base class’s member as they see fit. The sub-subclass (Derived
) uses new
to introduce the new API. Since you can only use new
or override
with a particular identifier only once per level of subclassing, you need two levels of subclassing to effectively use both on the same identifier.
So, in a way, you can change the visibility while overriding methods—it’s just a pain and there’s no syntax I know of to accomplish it with just one level of inheritance. However, you might have to use some trick like this depending on what interfaces you’re trying to implement and what your base class looks like. I.e., this may or may not be what you actually want to do. But I still wonder why C# does not just support this to begin with. IOW, this “answer” is just a re-expression of the OP’s question with a workaround ;-).
Upvotes: 2
Reputation: 32780
Changing the access modifier of a method in a derived type is pointless that's why it's not allowed:
Case 1: Override with a more restrictive access
This case is obviously not allowed due to the following situation:
class Base
{
public virtual void A() {}
}
class Derived: Base
{
protected override void A()
}
Now we could say:
List<Base> list;
list.Add(new Derived());
list[0].A() //Runtime access exception
Case 2: Overriding with a less restrictive access modifier
What is the point? Hide the method and you are done.
Obviously if someone calls through the base type they will not have access to the new method defined in the derived type but that is consistent with how the author of the base type wanted things to be so you have no "right" to change that. If you want the specifics of the derived class call from the derived class, in which case the new
method works perfectly fine.
EDIT: Expanding case 2
What I am trying to say in case 2, is that you already have the means to change accessibility of any method (virtual or not) if you want to change accessibility.
Consider the following code:
public class Base
{
protected virtual string WhoAmI()
{
return "Base";
}
}
public class Derived : Base
{
public new virtual string WhoAmI()
{
return "Derived";
}
}
public class AnotherDerived : Derived
{
public override string WhoAmI()
{
return "AnotherDerived";
}
}
With the new
keyword you have effectively created a new virtual method for your Derived
class with the same name and signature. Take note that it is ALLOWED to declare a new
method virtual
, so any class deriving from Derived
will be allowed to override it.
What is not allowed is to have someone do the following:
Base newBaseObject = new Derived();
newBaseObject.WhoAmI() //WhoAmI is not accessible.
But this fact has nothing to do with being able to override WhoAmI()
or not. Whatever the case this situation can never be because Base
does not declare a public
WhoAmI()
.
So in a theoretical C# where Derived.WhoAmI()
could override Base.WhoAmI()
there is no practical benefits in doing so because you will never be able to call the virtual method from the base class anyways, so the new
option already meets your requirements.
I hope this makes it clearer.
Upvotes: 33
Reputation: 273611
OK, I found a small note from Eric Lippert in the Annotated C# reference:
An overridden virtual method is still considered to be a method of the class that introduced it. The overload resolution rules in some cases prefer members of more derived types ... overriding a method does not "move" where that method belongs in this hierarchy.
So this is an intentional rule to prevent the 'brittle base class' problem and provide better versioning, ie less problems when a base class changes.
But note that it has nothing to do with security, type-safety or object-state.
Upvotes: 13
Reputation: 2772
if it had different access modifiers you can't really consider it the same method any more. kind of suggests a problem with the design of the model.
a better question would be why would you want to change the access modifiers?
Upvotes: 0
Reputation: 11531
If you change visibility modifiers from a more restrictive modifier to a less restrictive modifier you allow class clients access to methods designated for internal use. Essentially you've provided a means to alter class state that may not be safe.
Upvotes: 4
Reputation: 27441
You can make derived class's access less than the base's, but not more. Otherwise it would contradict base's definition and expose its components beyond what was intended.
Upvotes: 1
Reputation: 43217
Reasons are obvious. Security and Integrity of the objects.
In this particular example, what if external entities start modifying the property of the object which is protected according the base-class. Things will go haywire. What about the client-code that is written against the base-class to which all/any derived class must conform to.
Upvotes: 0