Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there ever a situation where derived class should hide …?

Perhaps a stupid question, but assuming base class A defines a virtual method V, is there ever a situation where it would make sense for a derived class C to hide A.V by declaring a new virtual method C.V with the same signature as A.V:

class Program
{
    static void Main(string[] args)
    {
        A a = new C();
        a.Print(); // prints "this is in B class"

        C c = new C();
        c.Print();// prints "this is in C class"
    }
}

class A
{
    public virtual void Print()
    {
        Console.WriteLine("this is in A class");
    }
}

class B:A
{
    public override void Print()
    {
        Console.WriteLine("this is in B class");
    }
}

class C : B
{
    public virtual void Print()
    {
        Console.WriteLine("this is in C class");
    }
}

Thank you

like image 678
flockofcode Avatar asked Dec 22 '22 01:12

flockofcode


2 Answers

Hiding inherited virtuals is not something that should be done as part of a deliberate design. Languages support virtual hiding to make object frameworks more resilient to future change.

Example: Release 1 of object framework X does not provide a Print() function. Bob decides to extend a few of the framework X objects by defining Print() functions in descendant classes of his own. Since he plans to override them in more specific classes, he also makes the Print() function virtual.

Later, Release 2 of object framework X is released. Bob decides to upgrade his current project to use Release 2 instead of Release 1. Unbeknownst to Bob, the object framework X team also decided Print() would be a useful function to have and so they added a virtual Print() in one of the base classes of the framework.

With virtual hiding, Bob's descendant classes containing Bob's Print() implementation should compile and run fine even though a different Print() now exists in the base classes - even with a different method signature. The code that knows about the base class Print() will continue to use it, and the code that knows about Bob's Print() will continue to use it. Never the two shall meet.

Without virtual hiding, Bob's code will not compile at all until he does some non-trivial surgery to his source code to eliminate the name conflict on Print(). Some would argue this is the "correct" thing to do (refuse to compile) but realistically any rev of a base library that requires revising existing working code will not go over well with customers. They will blame the framework for breaking everything and speak ill of it.

It would be reasonable for Bob to get a compiler warning about the base Print being obscured by Bob's print, but this isn't a fatal error. It's something that Bob should probably clean up (by renaming or eliminating his Print() function) as soon as possible to avoid human confusion.

like image 85
dthorpe Avatar answered Mar 08 '23 01:03

dthorpe


I have seen it used in scenarios where you want to automatically cast a member of a base class to narrower type from a subclass.

public interface IFoo { }

public class ConcreteFoo : IFoo { }

public abstract class Bar
{
    private IFoo m_Foo;

    public IFoo Foo
    {
        get { return m_Foo; }
    }

    protected void SetFoo(IFoo foo)
    {
        m_Foo = foo;
    }
}

public class ConcreteBar : Bar
{
    public ConcreteA(ConcreteFoo foo)
    {
        SetFoo(foo);
    }

    public new ConcreteFoo Foo
    {
        get { return (ConcreteFoo)base.Foo; }
    } 
}

In this scenario a reference to ConcreteBar can extract a reference to ConcreteFoo without the explicit cast while at the same time the Bar and IFoo variable references are none the wiser so all of their normal polymorphism magic still applies.

like image 40
Brian Gideon Avatar answered Mar 08 '23 03:03

Brian Gideon