简体   繁体   中英

Why should I want to create an object with base class reference?

    public class BaseClass
    {
        public virtual void Display()
        {
            Console.WriteLine("I am Base Class");
        }

        public void BaseClassMethod()
        {
            Console.WriteLine("I am Base Class Method");
        }
    }

    public class DerivedClass : BaseClass
    {
        public override void Display()
        {
            Console.WriteLine("I am Derived Class");
        }

        public void DerivedClassMethod()
        {
            Console.WriteLine("I am Derived Class Method");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            BaseClass bc = new BaseClass();
            bc.Display();
            bc.BaseClassMethod();

            Console.WriteLine("--------------");

            DerivedClass dc = new DerivedClass();
            dc.Display();
            dc.BaseClassMethod();
            dc.DerivedClassMethod();

            Console.WriteLine("--------------");

            BaseClass bc2 = new DerivedClass();
            bc2.Display();
            bc2.BaseClassMethod();
            //bc2.DerivedClass();  --> I can't reach b2.DerivedClass() method

            Console.ReadLine();
        }
    }

Hi everyone. I am trying to clear my mind about Why and where would I want to create and use derived class object from base class reference. I know how virtual works. I know derived class is a base class and I can override virtual methods. I can reach non virtual methods in base class. But I want to know where could and why would I want to use this style of object creation. Like in my last part of the example code;

BaseClass bc2 = new DerivedClass();

I can't reach derived class methods so I cant use derived class methods. But it is still derived class because of the new DerivedClass. If I use normal DerivedClass d = new DerivedClass(); style, I can use both class methods. I just cant find any reason and situation I would want to use this style. I would be glad if anyone show me in which situation I have to use derived class object from base class reference so I can understand this style is exist in language. I want to know WHY, I am not asking why this isn't working or something like that. Just want to know situations. Thank you.

There are two main usages:

1) Collections of multiple types

Lets change your example a little bit

public class Shape
{
    public virtual void Display()
    {
        Console.WriteLine("I am a Shape");
    }

    public void BaseClassMethod()
    {
        Console.WriteLine("I am Base Class Method");
    }
}

public class Square : Shape
{
    public override void Display()
    {
        Console.WriteLine("I am Square");
    }

    public void DerivedClassMethod()
    {
        Console.WriteLine("I am Derived Class Method");
    }
}



public class Circle : Shape
{
    public override void Display()
    {
        Console.WriteLine("I am Circle");
    }
}

class Program
{
    static void Main(string[] args)
    {
        List<Shape> shapes = new List<Shape();
        shapes.Add(new Square());
        shapes.Add(new Circle());

I have a list that can hold Circles, Squares, and generic Shapes all in a single collection.

2) Polymorphism

Continuing on from the previous code

         foreach(Shape shape in shapes)
         {
             shape.Display();
         }

we don't know what kind of Shape the variable shape is, however we do know that whatever kind it is it will have a Display() method we can call and it will show the correct information.

Polymorphism is useful when you need to call a function on something but you don't know the specific type that something will be because you are pulling a collection of base types like above, or you want to write a function that can take in any kind of Shape because the function does not need to know the specific kind to do it's work.

    public static void LogDisplay(Shape shape)
    {
         Console.WriteLine("I am about to call shape.Display()");
         shape.Display();
         Console.WriteLine("I am just called shape.Display()");
    }

My favorite example, because people can understand the use, is logging. Imagine I create a website. When I'm developing the site, I want to log to my file system, because it's easy to access. When I deploy the website, I want to log to the event log, because maybe I don't have direct access to the file system on that machine.

However, I only want to change where things are logged, I want the base class to structure how the actual text looks. So I have my base class that formats text:

public abstract class BaseLogger
{
     public abstract void LogException(Exception ex);
     public abstract void LogUserMessage(string userMessage);

     protected string GetStringFromException(Exception ex)
     {
        //....
     }

     protected string GetStringFromUserMessage(string userMessage)
     {
        //....  
     }
}

Now I can have a class that logs to the File System:

public class FileLogger : BaseLogger
{
    public FileLogger(string filename)
    {
        //initialize the file, etc
    }

    public override void LogException(Exception ex)
    {
        var string = GetStringFromException(ex);
        File.WriteAllLines(...);
    }

    public override void LogException(Exception ex)
    {
        var string = GetStringFromUserMessage(ex);
        File.WriteAllLines(...);
    }
}

and my class that logs to the Event Log:

public class EventLogger : BaseLogger
{  
    public EventLogger()
    {
        //initialize the eventlog, etc
    }

    public override void LogException(Exception ex)
    {
        var string = GetStringFromException(ex);
        EventLog.WriteEntry(...);
    }

    public override void LogException(Exception ex)
    {
        var string = GetStringFromUserMessage(ex);
        EventLog.WriteEntry(...);
    }
}

Now in my program, I only care that I have a BaseLogger when I inject one into my classes. The implementation details are irrelevant, I just know that I can LogException and LogUserMessage no matter what I'm using.

When I'm using the logger I benefit from not caring which derived class I use . That's the benefit of treating each derived class like a base class. I can swap them out without my program caring.

There are many reasons to do this, mostly to do with code re-usability and extensiblity, which in other words, to make a small change or enhancement easily without needing to rewrite a whole lot.

A real world example (which happens frequently) is the case where you have different customers using your software which may require you to support different databases (or even different table structures). So in order to do that, you can derive implementations from a common base class, and vary in the implementation details without affecting the rest of the program.

This also follows the design principle "Program to an 'interface', not an 'implementation'" which is explained in the GoF design pattern book

public abstract class ProviderBase
{
    public abstract Employee[] GetAllEmployees();
}

public class MySqlProvider:ProviderBase
{
    public override Employee[] GetAllEmployees()
    {
        string select = "select * from employees";

        //query from mysql ...
    }

}

public class MsSqlProvider : ProviderBase
{
    public override Employee[] GetAllEmployees()
    {
        string select = "select * from user u left join employee_record e on u.id=e.id";

        //query from mysql ...
    }
}

Then in the main program you may be able to change the type of database implementation by configuration or Dependency Injection

ProviderBase provider = null;
if(databaseType == "MySql")
{
    provider = new MySqlProvider();
}
else if (databaseType == "MsSql")
{
    provider = new MsSqlProvider();
}

var employees = provider.GetAllEmployees();
//do something

I believe a lot of the reasoning behind the availability of using derived classes has to do with minimizing repeated code.

To reference a real life example... If I was to ask you to describe the attributes and abilities of a car, and then was to ask you to do the same for an electric car, you would find that much of the attributes and abilities are shared by both. So instead of having it be two completely separate classes, it would be more efficient to create the base class Car, and derive electricCar from that. Then you will only need to account for the specific differences of the electric car within the derived class, and all the shared attributes and abilities will carry over.

Hope this helps you understand the usefulness of base classes and derived classes. Very oversimplified but I feel it may help you grasp the concept!

The main reason to use a base class is reusability and polymorphism

So you could create the class depending on a condition:

BaseClass bc
if(case1)
    bc = new DerivedClass1();
else
    bc = new DerivedClass2();

In the following application you can use bc even if you don't know what kind of derived class it is at compile time. You can pass it eg to other functions and call the overridden methode:

bc.Display();

Derived class methods can only be used when you know what kind of derived class you actual have. Then you can do a conversion.

DerivedClass1 dc = bc as DerivedClass1;
dc.DerivedClassMethod()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM