Inheritance disasterFiled Under: Weekly Tuesday Dose of goodness
- Private Heap Disaster
- Debugging Disasters
- ‘this’ pointer disaster
- Inheritance disaster
Dear all,
This week’s article will be rather short because I’ll only be focusing on 1 single issue that I’ve come across. Some may think that it’s complete stupidity while others may be more sympathetic.
In any case, this is a disaster scenario caused by misunderstanding or abusing the use of Object Oriented programming in C++
Read on to find out more…
Introduction
We all know that C++ is an OO language. Therefore we can perform many things with C++, some of which can’t even be fulfilled properly by languages like Java. I’ll explain my statement in the future.
One of the shining mechanisms of Object-Oriented Programming is of course, inheritance. To many it’s a feature that is widely abused to reduce the amount of codes written and also poor attempts to improve reusability.
If done correctly, a framework or engine can easily become popular with programmers. Otherwise, it increases coupling to very dangerous levels and can easily cause the whole system to collapse by design failures.
Scenario
The scenario I have here today is based on C++ only. So, sorry Java and C# folks, you may have to sit this one out this time. But still, it may be something interesting to read up.
Once I was asked to resolve a very weird memory issue encountered with one of my customers. Basically, this customer was trying to make this structure compatible with a linked list node.
Reason? So that he can add structures into a linked list!
Now, this is one classic example where a Java-style programmer tries to make things happen using the Java way in C++. This is suicidal.
So we’re looking at a piece of code which looks like this:
struct MyStructure : public cLinkedListNode {
…
};
By understanding that structs and classes are alike, this is supposed to work right?
Well… yeah, technically, if this is the only predicate, then yes. However, another rule or practice will easily destroy this whole thing - All structures should always be memset to zero before usage.
So… I do something like this:
MyStructure instance;
memset(&instance, 0, sizeof(MyStructure));
What happens next?
You’ll get a very tight slap on your face!
Why? Simple, whenever you inherit another class, the first 4 or 8 bytes, depending on your system architecture and struct alignment, will contain an address to a table known as the vtable.
Without this table, it’s impossible for polymorphism to work and setting it to null certainly ensures that all your virtual methods will lead to disaster.
Conclusion
While it’s important to understand C++ semantics, it’s also important to know that structures are not recommended in a pure C++ environment.
Surely, a mixture C and C++ is possible and even things like temporary variables in C++, which in pure C environments, are illegal, can be used with proper control and understanding.
The problem arises when both standards are mixed wrongly as mentioned in the example above. In that case, neither can the structure be used the C-style way nor can it be added into a linked list just like that.
Solution?
Well… if C++ is to be used, either convert the structure into a class or implement a default constructor for its members. This is allowed in C++ by the way.
Next, the implementation of the linked list is wrong too.
This is C++, not Java. There’s no notion of an Object being the all generic object of every possible object out there. Thus comes this language facility known as - templates.
For example, Strideslib’s version of the linked list is known as cLinkedList<T>. Where T must be specialized in order for the template to be usable. It’s extremely type-strict, thus specializing it with a normal variable is not recommended.
For example: cLinkedList< MyStructure >
This example above requires MyStructure to have a default constructor or else it may not compile. On top of that, it should be used in conjunction of a pointer container such as cSmartPtr<T>.
For example: cLinkedList< cSmartPtr< MyStructure > >
This way, you reduce the amount of work done by the linked list; the copy assignment operator doesn’t have to be invoked everything you get something out from the linked list.
Unless there’s a very strong reason for inheritance, which otherwise, fail completely in the example above, composition or aggregation should be used instead.
I’ll cover these few terms in one of the next few articles.
If not, I’m done for the week. I’ll probably be taking a brief hiatus to work on other things very soon.
Have a great week ahead!
Signing off,
Jeremy
- Permalink
- Admin
- 6 Jul 2010 12:04 PM
- Comments (1)
July 13th, 2010 at 9:34 am
[...] Now we just take a short moment to pull back things a little. We all know that classes and structs are very similar with the exception that classes have methods, access modifiers and inheritance capability. Structures can do that too - with disastrous results of course - as mentioned in my previous post here. [...]