45

Coming from a C++ background, this came as a surprise to me. In C++ it's good practice to make virtual functions private. From http://www.gotw.ca/publications/mill18.htm: "Guideline #2: Prefer to make virtual functions private."

I also quote Eric Lippert's blog, from Knights-knaves-protected-and-internal:

Private virtual methods are illegal in C#, which irks me to no end. I would totally use that feature if we had it.

I understand that in C#, you wouldn't be able to override a private virtual method in a derived (but not nested) class. Why is this the case? In C++ the access specifier has nothing to do with whether you can override a function or not.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Jon
  • 5,275
  • 5
  • 39
  • 51

7 Answers7

42

I note that there are two questions here. In the future you might consider posting two questions instead of combining two questions in one. When you combine questions like this often what happens is only the first one gets answered.

The first question is "why are private virtual methods illegal in C#?"

Here are the arguments against the "private virtual methods" feature:

  1. private virtual is only useful when you have a nested derived class. This is a useful pattern, but far less common than the non-nested derived class situation.

  2. If you desire to restrict the ability to override the method in non-nested derived classes then you can do so by restricting the ability of non-nested classes to derive from the base class; make all the base class constructors private. Therefore private virtual is not necessary to prevent overriding; protected virtual is sufficient, because the only derived classes will be nested.

  3. If you desire to restrict the ability to call a method in a non-nested derived class then you can make the method internal virtual and then tell your coworkers to not use that method. It is irritating to have this not be enforced by the compiler, but the compiler does not enforce any other semantic constraint on how a method is supposed to be used either; getting the semantics right is your business, not the compiler's, and you have to enforce that with appropriate code reviews. Therefore private virtual is not necessary to prevent calling; internal virtual plus code reviews is sufficient.

  4. It is possible to implement this pattern already with existing parts:

    abstract class C
    {
        private int CF() { whatever; }
        private Func<int> f;
        public C() { f = CF; } 
        private int F() { return f(); }
        private class D : C
        {
            private int DF() { whatever; }
            public D() { f = DF; }
        }
    

    Now I have a method F which is effectively virtual, but can only be "overridden" by derived nested classes.

Since in every case either protected, internal or protected internal does the trick, private virtual is unnecessary. It's almost never the right thing to do, since you have to be already committed to using the nested derived class pattern. So, the language makes it illegal.

The arguments for are:

There have been times in real code when I've want a virtual method to be a private implementation detail of a class that I want to be extended both by non-nested internal classes and nested internal classes. Having to enforce the invariant that the internal method not be called by my coworkers is vexing; I'd like that to be enforced by the compiler without me having to jump through crazy hoops like making a field of delegate type, etc.

Also, there's simply the matter of consistency and orthogonality. It seems weird that two things that ought to be independent -- accessibility and virtualness -- have an effect on each other unnecessarily.

The arguments against the feature are pretty strong. The arguments for are pretty weak. Therefore, no such feature. I'd personally like it very much, but I totally understand why the design team has never taken me up on it. It's not worth the cost, and I would hate to not ship a better feature because we spent budget on a feature that benefits almost no one.

The second question is "Why in C# are you not able to override a private virtual method in a derived non-nested class?"

There are several reasons.

  1. Because you can only override what you can see. A private method is a private implementation detail of a base class and must not be accessible.

  2. Because allowing that has serious security implications. Remember, in C++ you almost always compile code into an application all at once. You have the source code for everything; everything is essentially "internal" from the C++ perspective most of the time. In C#, that's not at all the case. Third party assemblies can easily get at public types from libraries and produce novel extensions to those classes which can then be used seamlessly in place of instances of the base class. Since virtual methods effectively change the behaviour of a class, any code which depends for security reasons on invariants of that class needs to be carefully designed so that they do not depend on invariants guaranteed by the base class. Restricting accessibility of virtual methods helps ensure that invariants of those methods are maintained.

  3. Because allowing that provides another form of the brittle base class problem. C# has been carefully designed to be less susceptible to the brittle base class problem than other OO languages. If an inaccessible virtual method could be overridden in a derived class then that private implementation detail of the base class becomes a breaking change if altered. Providers of base classes should be free to change their internal details without worrying overmuch that they've broken derived classes which depend on them; ideally only the public, documented interface to a type needs to be maintained when implementation details change.

svick
  • 236,525
  • 50
  • 385
  • 514
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 4
    Allowing derived classes to override a private virtual member but not call it except via chain to `base` would allow the base class to ensure that all calls to the method were wrapped in base-supplied code. For example, `private virtual doPerformAction() {...}; public doPerformAction {lock(myThing) { doPerformAction(); }`. Since that doesn't work, is there any other way to enforce that pattern? – supercat Dec 06 '13 at 23:40
  • What about sealed classes? Don't private overrides make sense in something that cannot be inherited from? – gravidThoughts Sep 20 '14 at 02:43
  • @EricLippert Interesting, you're saying that _supporting_ `private virtual` incurs a development cost. That means that there would have to be code specifically enabling `private virtual`. To a layman's eye, there's no reason for these features to be interdependent, so my assumption was that there was code that was specifically responsible for checking whether a `virtual` method is `private` and marking that as an error. That would make not-disallowing them cheaper. Are there technical differences between how code would be generated for a non-`private` `virtual` and a `private virtual`? – V0ldek Jan 05 '20 at 17:49
  • @V0ldek: You've put your finger on an important point that I often make on this site: *every feature incurs costs*, and that includes "negative" features -- that is, features that enforce a rule that some behaviour that could be legal is illegal, like private virtual. In those cases the language designers must weight the costs of enforcing the rule against the user benefits of preventing an arguably bad pattern. – Eric Lippert Jan 05 '20 at 23:24
  • *'is only useful when you have a nested derived class'* – don't agree; the pattern might be used to guarantee some meaningful overall behaviour, like e.g. `doSomething() { setupContext(); doVirtualSpecific(); cleanupContext(); }` while calling `doVirtualSpecific` without the context set up might be faulty in *any* case... – Aconcagua May 24 '23 at 11:50
  • *'It is possible to implement this pattern already with existing parts'* – how would a class inheriting from `C` override `f` without being able to call what it sets to `f`??? *That* is what would be virtual private! – Aconcagua May 24 '23 at 12:15
15

Because private methods can ONLY be accessed from the class defining them, hence a private virtual method would be useless. What you want is a protected virtual method. A protected method can be accessed by the class defining it and any subclasses.

EDIT:

By providing private and protected keywords C# allows you more granular control over your methods. That is private means completely closed and protected means completely closed apart from subclasses. This allows you to have methods that only your superclass knows about and methods that subclasses can know about.

Darko
  • 38,310
  • 15
  • 80
  • 107
  • 13
    `private virtual` would still be accessible from inner classes (read the whole thread on Eric's blog for a longer discussion). They are useful if you are creating a type hierarchy and want to restrict inheritance to only classes that you know about/control. To be honest, my thinking is that they didn't include it because `internal virtual` does *almost* the same thing. – Dean Harding Jun 21 '10 at 05:41
  • Protected is probably clearer than private for this. Imagine if you have a baseclass with a public method ("callPrivate") which calls a private member. Imagine subclass overrides the private member. If you had a call like (base.callPrivate()) in your subclass, should it call the subclass's private member or the baseclass's private member? – Matt Mitchell Jun 21 '10 at 06:06
  • What if I want to make a method overridable in the derived class ,BUT not visible to the instance of the derived class .I think this could have been quite useful to protect method from being called by the instance. – Thunder Feb 10 '12 at 10:14
  • They are *not* useless; you could enforce something like `void doSomething() /* non-virtual or sealed*/ { setupContext(); doSpecificVirtual(); cleanupContext(); }` while `doSpecificVirtual` called without the context set up might be meaningless or faulty. – Aconcagua May 24 '23 at 12:21
5

I would guess the reason is that internal virtual does almost the same thing as private virtual and is somewhat less confusing for those not familiar with the private virtual idiom.

Whereas only inner classes could override private virtual methods, only classess in your assembly can override internal virtual methods.

Dean Harding
  • 71,468
  • 13
  • 145
  • 180
  • I can already prevent my coworkers from making classes that *override* those methods by preventing them from making classes that *inherit from* the base class. (With a private constructor.) What I want is to make an extension point in an internal abstract base class which can only be *called* by a derived nested class. – Eric Lippert Jun 21 '10 at 06:15
  • @Eric: Yeah, I understand that, I was just speculating on reasons why it was not available. I do think that, certainly going by the other answers we've seen on this question at least, the "less confusing" argument seems valid as well and if `internal virtual` + private constructor gets you 99% of the way there, then why bother? :) – Dean Harding Jun 21 '10 at 06:19
  • *Protected* virtual is a better alternative than internal virtual. No need for internal unless you need assembly wide access. – Ash Jun 21 '10 at 07:18
  • 1
    Internal virtual is a better alternative than protected virtual. The ability to override a virtual method is the ability to change the behaviour of a class, and doing so can have security implications. It is better to restrict that ability to classes in your own assembly, which you control, than to have to build a system which mitigates the risk of partially trusted third parties undermining your invariants to harm your users. – Eric Lippert Jun 21 '10 at 07:33
  • @Eric, If you allowed whitespace in identifiers then you could at least _hide_ them from your coworkers :) – Drew Noakes Jun 21 '10 at 07:57
2

In C# (and in the CLI, as far as i've seen), "private" has a pretty clear and unambiguous meaning: "accessible only in this class". The concept of private virtuals screws that all up, not to mention making namespaces a bit of a minefield. Why should i have to care what you've called a method i can't even see, and get a compiler warning for happening to have chosen a name you already snagged for it?

cHao
  • 84,970
  • 20
  • 145
  • 172
2

Because C# does not have any mechanism for providing public/private/protected inheritance, which is what you are actually after.

Even in C++, private members cannot be accessed by derived classes, but they can limit the base class visibility by specifying inheritance visibility:

class Derived : /*->>*/private/*<--*/ Base {
}

C# provides a whole bunch of other things in order for you to control the visibility of your class' members. Between protected and internal, you should be able to get the hierarchy exactly as you want.

IMHO C# enforces stronger IS-A relationship via single base class inheritance, so it makes sense that if a car has an engine, a BMW subclass shouldn't be able to hide it.

C++ supports multiple inheritance which is a less stricter IS-A relationship - it's almost like a HAS-A relationship where you can bring in multiple unrelated classes. Because of the ability to bring in multiple base classes, you want tighter control over the visibility of all of them.

Igor Zevaka
  • 74,528
  • 26
  • 112
  • 128
  • 2
    Inheritance is **always** about the IS-A relationship, whether that is single inheritance or multiple inheritance. Moreover, there are cases where MI makes sense, but it's not easy to use well and is therefore best avoided if you've not got a proper problem-domain reason for doing it. (HAS-A is modeled just fine by fields.) – Donal Fellows Jun 21 '10 at 08:01
  • In c++ private members cannot be accessed – but you *can* override private virtual functions – or even *must*, if pure virtual (corresponds to abstract). – Aconcagua May 24 '23 at 12:25
2

Use:

virtual private protected

Has the exact functionality of what you would expect a virtual private method to do. Can't be accessed outside the class but can be overriden by subclasses

Joben
  • 51
  • 6
1

Let me make this clear: C# is not C++.

C# is designed multiple decades after C++ and is built using advancing insights over the years. In my humble opinion C# is well defined and finally handles object orientation the right way (imho). It includes the internal statement for a reason and does not allow you to "virtualize" and override private methods. For a reason.

All the issues described earlier (inner classes overriding private virtual methods, using the abstract factory pattern this way etc...) can be easily written in a different way using interfaces and the internal statement. Having said that, I must say that it is fairly a matter of taste whether you like the C++ way or the C# way.

I prefer to use descriptive code (code that speaks for itself, without using comments) and I use interfaces instead of deep inheritance. Overriding private virtual methods feels like hacking or spaghetti to me, regardless if it's common practice, an often used pattern or gets the job done.

I've been developing in C++ for almost 1.5 decades and I never came across the necessity for overriding private methods... ( I can see the comments flying in :-) )

Rob Vermeulen
  • 1,910
  • 1
  • 15
  • 22