I've been reading Stroustrup's "The C++ Programming Language" and he mentions "abstractions" a lot:
Many of the most flexible, efficient, and useful abstractions involve the parameterization of types (classes) and algorithms (functions) with other types and algorithms
and
C++ is a language for developing and using elegant and efficient abstractions.
Is this in any way related to abstract classes in C++? Or with using polymorphism, inheritance, or templates?
Could someone give an example please?
Your car is a great example of abstraction. You can start a car by turning the key or pressing the start button. You don't need to know how the engine is getting started, what all components your car has. The car internal implementation and complex logic is completely hidden from the user.
The main purpose of abstraction is hiding the unnecessary details from the users. Abstraction is selecting data from a larger pool to show only relevant details of the object to the user. It helps in reducing programming complexity and efforts.
Abstraction can be of two types, namely, data abstraction and control abstraction.
abstraction (n) - the quality of dealing with ideas rather than events
— source: Oxford English Dictionary
Stroustrup is not referring to abstract classes or other specific ideas in programming. Rather, he is referring to the word abstraction itself.
Abstractions are mental helpers. They help us think in "theory" rather than direct application. Mathematics is the art of abstraction. Programming is the art of applied abstractions.
Abstractions help us form mental models, such as hierarchies, to help us think of things. Polymorphism is possible because of abstractions. Let's take a look at an example.
I have an Oleksiy Dobrodum. I refer to it as an Oleksiy Dobrodum, I treat it like an Oleksiy Dobrodum, all it will ever be is an Oleksiy Dobrodum. Everything I do to this Oleksiy Dobrodum is specifically for it. We're now on the 1st level of abstraction, or the most specific we'll ever be when working with this Oleksiy Dobrodum.
Recently I acquired a Zach Latta, so now I have both an Oleksiy Dobrodum and a Zach Latta.
I could refer to them both individually, so as an Oleksiy Dobrodum and as a Zach Latta, but that would quickly grow redundant and prove to not be flexible. Instead, we can simply group Oleksiy Dobrodum and Zach Latta together and call them Humans. We have now achieve abstraction level 2. Instead of dealing with each person individually, we can refer to them as Humans. By doing this, we have abstracted away the "implementation", or the specific details of each person and have started focusing on the ideas, therefore we are now thinking in the abstract.
Of course we can abstract this further, but hopefully you're starting to get the idea behind abstractions. The key takeaway from this is that an abstraction hides the details (or implementation). By hiding the details in our Humans abstraction, we allow ourselves to speak in generalities. We'll talk briefly on how this applies in programming in the next section.
Now that we've touched briefly on what an abstraction is, let's apply it. Polymorphism is possible because of abstractions. Following the model of the previous example, say we have the following two classes:
class OleksiyDobrodum
name = "Oleksiy Dobrodum"
smarts = :mega-smart
mood = :happy
favorite_candy = :chocolate
end
class ZachLatta
name = "Zach Latta"
smarts = :so-so
mood = :indifferent
hair_color = :brown
end
If I want to interact with an instance of ZachLatta
I must refer to it specifically. The same goes for OleksiyDobrodum
instances.
zach = new ZachLatta
print zach.name
oleksiy = new OleksiyDobrodum
print oleksiy.favorite_candy
If I create an abstract class called Human
and have both OleksiyDobrodum
and ZachLatta
inherit from it, then I can abstract away the implementation of both classes and simply refer to both instances of them as Human
.
class Human
name
smarts
mood
end
class OleksiyDobrodum < Human
name = "Oleksiy Dobrodum"
smarts = :mega-smart
mood = :happy
favorite_candy = :chocolate
end
class ZachLatta < Human
name = "Zach Latta"
smarts = :so-so
mood = :indifferent
hair_color = :brown
end
Our class diagram now looks like the following:
I could ramble on about implementation forever, but let's move on to our key takeaways.
In generic programming, abstractions have a precise meaning, and are called "concepts". A concept is defined as follows:
A concept is a set of requirements consisting of valid expressions, associated types, invariants, and complexity guarantees. A type that satisfies the requirements is said to model the concept. A concept can extend the requirements of another concept, which is called refinement.
Implementing a concept into real code can be done is several ways. The classical OOP approach is to write an abstract base class providing the valid expressions and associated types. The concrete derived classes then provide the invariants and the complexity guarantees. For templates, the valid expressions are more implicit and only checked after instantiation. Template implementing concepts are a form of duck typing: if it looks like a duck, quacks like a duck, ....
The C++0x development process devoted a lot of effort to make concepts directly expressible into code, but it was not incorporated into the C++11 Standard. However, a Concepts Lite version is likely going to appear into the next C++14 Standard.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With