Suppose I have the usual class Animal
abstract class and the class Dog : public Animal
class Cat : public Animal
that makes it a concrete class you can instantiate an object from. Suppose further that you have a function foo(Animal a)
, taking either cats or dogs as objects. C++ used to, in the early days, compile to C, and would build a vTable
maintaining the objects there.
But a student of mine asked me this question: before these concepts were usual talk among programmers, how did they actually do it in their day-to-day coding in C? What was (is?) the idiomatic way to program these concepts in C?
I've sifted through the linux kernel, and other OSS projects, but I haven't been able to find a clear pattern: sometimes it's unions (for different structs), sometimes it's function pointers, etc. but I would like a straight answer from knowledgeable people in industry who've done and have a lot of experience with C.
In one sentence: what is idiomatic C for inheritance and polymorphism?
Inheritance is where a child class inherits the fields and methods of the parent class. The child class can then also define its own methods. Polymorphism in C# is a OOPs concept where one name can have many forms.
What is Polymorphism in C#? Polymorphism in C# is an OOPs concept where one name can have many forms. For example, you have a smartphone for communication.
For example, you have a smartphone for communication. The communication mode you choose could be anything. It can be a call, a text message, a picture message, mail, etc. So, the goal is common, that is, communication, but their approach is different. This is called Polymorphism.
The syntax of inheritance is very simple and straightforward. The operator ':'is used to indicate that a class is inherited from another class. Remember that in C#, a derived class can't be more accessible than it's base class. That means that it is not possible to declare a derived class as public, if it inherits from a private class.
Simple programs, such as those written for school assignments, implement polymorphism using a structure that consists of a union and optionally an enum as the type discriminators. Each "method" then contains a switch statement that calls into the function appropriate for the subtype. Obviously this doesn't scale to more systems that require being able to add subclasses without changing the definition of the base class.
Polymorphism itself is easily expressed with function pointers that receive an explicit self
argument. Open-ended inheritance can be achieved with the "inherited" structure embedding its superclass:
struct base {
// ... members here ...
};
struct inherited {
struct base base;
// ... inherited members here ...
};
Pointers to struct inherited
may be safely cast to struct base *
, a practice explicitly blessed by the C standard. These casts are typically hidden behind macros, which may even perform runtime type checking, where possible.
Implementing this is quite unwieldy, since there are no templates, no automatic invocation of destructors, no exceptions, and no STL. In other words, error handling and destructor invocation must be carefully handled by the programmer, and type variance must be handled either by callbacks at run-time (consider the difference between std::sort()
and qsort()
) or by hard to maintain preprocessor tricks.
Despite the difficulties, it is certainly possible to implement a meaningful subset of C++ functionality in C, and even a semblance of simplicity of C in the process. To study real-world examples of this approach being taken to production level, take a look at the implementation of the CPython interpreter, or the glib object system used by GTK+.
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