What if you were writing a class that you wanted to be a base class? A class designed from the very beginning to bring together other classes with common behavior. What if you also wanted to guarantee that this class could never be created by itself? That it must always exist as a base class for some other class? All you have to do is make your class abstract. Then it can only be instantiated as part of another class that derives from your class. This episode will explain why you might want to do this and how.
Because one of the biggest reasons to use inheritance is so you can override a method and provide your own implementation, then it makes sense that a big reason for you to plan for inheritance is so that your methods can be overridden.
But what if your base class doesn’t have the ability to provide its own implementation. If you leave the method out, then it’s no longer part of the base class. You want it to be included in the base class so you can still make use of the virtual behavior. The solution is to make the method a pure virtual method and declare that there is no implementation at the base class level. This makes your base class abstract.
An abstract class cannot be instantiated, or created, on its own. It must always serve as the base class for one or more other classes. As soon as you have a derived class that fully implements all the pure virtual methods, then that derived class becomes concrete. That’s a class that can be created. When you create a concrete class, you end up creating any abstract classes just like any other base class.
Making a class abstract just ensures that it will never exist on its own and must always be part of another derived class. It also gives you the ability to declare methods at the base class level which will be guaranteed to be implemented by at least one of the derived classes.
Listen to the full episode for more about abstract classes, or you can also read the full transcript below.
One of the main reasons for using inheritance is so that you can override a base class method and provide your own implementation of that method. We can flip this reason around to say that one of the main reasons to plan for inheritance is to allow a derived class to provide its own implementation. You do this by making one or more of your class methods virtual.
A virtual method is one that you provide a default implementation but recognize that other classes might want to change that implementation with their own.
Sometimes, there’s no good implementation that you can provide at the base class level. You just don’t have enough specific knowledge about how your base class will be used or each derived class is so different that there’s just not enough common ground to provide a reasonable default implementation. You could just leave this method out of the base class since you have no way to implement it. But that means the method won’t exist in your base class. If you’re working with a group of derived classes and referring to all of them through your base class, then you can’t call this method. It doesn’t exist in the base class.
A better approach is to go ahead and declare the method in your base class and make it virtual but just don’t provide an implementation. Can you do this? Yes, but it has a side effect. Your base class is no longer complete and can’t exist on its own anymore. It becomes abstract.
This requires a little more than just forgetting to implement a method. If you write your class with several methods and don’t implement one of them, then some languages might not complain at all as long as you never actually try to call your missing method. In order to do this properly, you must declare that the method exists, is virtual, and that it’s purposely being omitted. Different languages will have different ways to specify this intent. Doing this makes the method a pure virtual method or an abstract method. It also makes the class an abstract class. Some languages might even allow you to declare your class to be abstract even without needing to declare any abstract methods.
Now, your class might have lots of data members and maybe even several other methods that are complete. All it takes though is just one abstract method to turn your entire class into an abstract class.
This allows you to declare your intent that your abstract method will exist and must be implemented in some derived class. That’s enough for your to be able to call that method from your base class now.
Does this mean that the abstract method needs to be implemented right away in some class that derives directly from your base class? No. If you create a derived class from an abstract class and don’t override all of the abstract methods, then your new class will also be abstract. Only when some derived class finally implements all of the abstract methods will you end up with a class that’s concrete. A concrete class is one that you can instantiate or create new instances of. Concrete classes are guaranteed to not have any remaining abstract methods.
Nowadays, we deal with abstract concepts all the time in the real world but it wasn’t always like this. We all know how to count 1, 2, 3, etc. but what are numbers, really? They’re abstract concepts of a quantity. In ancient times, this was unheard of. It didn’t make sense to count things that didn’t exist. You could count 1 sheep, 2 sheep, 3 sheep, etc. but 1, 2, and 3 by themselves were meaningless. And the idea of zero? THAT took a long time for people to accept. Negative numbers? How could you possibly have -1 sheep? You either had one or more sheep or none. You didn’t need a number zero to tell you that you had no sheep and you definitely didn’t need negative numbers. Yet despite all this, we accept the concept that some things are abstract very easily today.
You can introduce abstract classes into your design which will guarantee that some derived class will implement the methods you declare even if your base class has no idea of how this method will be implemented. All the base class cares about is that the method exists and will eventually be implemented.