inheritance tree in one file

Started by
9 comments, last by SmkViper 9 years, 6 months ago

C++, I'm considering putting all classes from an inheritance tree in one cpp file (one per tree, and I don't use multiple inheritance.. yet anyway). Can you see any downsides to this? I'm not particularly experienced with big code bases, but I think I'll be more comfortable with them all in one file. Any comments on this in general?

-potential energy is easily made kinetic-

Advertisement

If you're comfortable working that way, do it. There's no rule to follow.

If you're part of a team you should check with the rest, because it could make the merges of changes more difficult, but that's the only real downside I can think off.

A possible downside is compile time, which depends on how big the file is, where the classes are used in other files, how often you think you're going to edit just a portion of the file/header, and how soon you think you may want to make major changes to the class(es). If you, for instance, change just one thing in just one function declaration for just one class, that file and any other files using those classes will be recompiled.

Another consideration (depending on the size and complexity of the file) is whether you're going to be able to find things a month from now. It's easier to scan through a file for a single class, maybe a couple hundred lines, for something, than trying to remember which class has what in a megafile.

However, if you project is small and your compile times are just a few seconds, do what's comfortable.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Can you see any downsides to this? I'm not particularly experienced with big code bases


Only that you maybe don't actually want inheritance (it's especially in big codebases where it starts to break down and doesn't work well anymore).

Though honestly, I think "can you fit the whole hierarchy in a single reasonably-sized .cpp file" might be a great litmus test for whether or not you should even be using inheritance in this case. smile.png

Sean Middleditch – Game Systems Engineer – Join my team!


If you're part of a team you should check with the rest, because it could make the merges of changes more difficult, but that's the only real downside I can think off.

Thats actually a big downside if I ever go with a team or make my source code available and people want teams.


If you, for instance, change just one thing in just one function declaration for just one class, that file and any other files using those classes will be recompiled.

Wait doesn't that happen irregardless of file organization?


(it's especially in big codebases where it starts to break down and doesn't work well anymore).

What starts to breakdown? Inheritance? if so what makes you say that?

Finally another question sort of related to this topic. Lets say I have a base class with some accessors that will trivially be inlined, if I have a child to this class in another file and linktime code generation is disabled will they be inlined when used in the child class? I guess I'm just asking if the source code for the parent is considered in the same translation unit as the child when the child gets compiled?

edit - also if code always gets inlined so the non-inlined versions never get called, will dead code elimination remove this code, or will it get left in for compatibility reasons?

-potential energy is easily made kinetic-

Wait doesn't that happen regardless of file organization?
If you, for instance, change just one thing in just one function declaration for just one class, that file and any other files using those classes will be recompiled.

If a file includes another file, and the second file changes, the first file must be recompiled. The use of inheritance forces some classes to have dependencies of this sort by definition. There are often times when favouring composition over inheritance prevents this sort of thing since the individual component classes don't necessarily depend on each other.


Buckeye, on 16 Oct 2014 - 11:22 PM, said: If you, for instance, change just one thing in just one function declaration for just one class, that file and any other files using those classes will be recompiled.

Wait doesn't that happen irregardless of file organization?

No. Consider - if you have a base class and (e.g.) 10 classes derived from base, the base class has it's own header and cpp, and each derived class has it's own header and cpp file. If another file elsewhere depends only on (e.g.) "DerivedClass07," with #include "DerivedClass07.h," that file need not be recompiled if changes are made to anything but the base class header and "DerivedClass07.h"

I'm not recommending that you necessarily organize it that way. You asked for potential downsides. That's one of them.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

What starts to breakdown? Inheritance? if so what makes you say that?


In the context of "deep hierarchies" (not just big codebases; I misspoke a little there) there's a ton of literature on why inheritance doesn't work.

Even in small contexts, inheritance is very often abused by novice coders. Inheritance should be used for computational is-a relationships, not real-world modeling of taxonomies. Once you move to only using semantics and inheritance where a computer and not a human brain needs to see it, you'll find you're using relatively little inheritance.

Finally another question sort of related to this topic. Lets say I have a base class with some accessors that will trivially be inlined, if I have a child to this class in another file and linktime code generation is disabled will they be inlined when used in the child class? I guess I'm just asking if the source code for the parent is considered in the same translation unit as the child when the child gets compiled?


Inlining is a hint at best, and different implementations with different options will do it differently; the standard makes no guarantees here. C++ compilers don't see things in terms of parents and children (which again illustrates that computers don't think in terms of inheritance); they see things in terms of translation units (.cpp files) normally (and only inline things they can see via includes) and maybe sometimes across whole modules (executables, shared libraries, etc.) in many LTO implementations. LTO implementations typically aren't as capable as the normal TU machinery for various reasons, at least today.

Short version: there's no way to know and if for some reason you actually care about the specific, test your specific compiler on your specific code and look at the output.

edit - also if code always gets inlined so the non-inlined versions never get called, will dead code elimination remove this code, or will it get left in for compatibility reasons?


It depends on many factors. If the address is taken, the code cannot be removed. If the symbol is exported (remember this is the default on most UNIX-like systems!) then it can't be removed. If the compiler doesn't know if the address will be taken or not for sure, it can't be removed. If the optimization level isn't high enough or the compiler's LTO features aren't powerful enough, it can't be removed. Again, test your specific compilers against your specific code, as there are no guarantees.

Sean Middleditch – Game Systems Engineer – Join my team!


No. Consider - if you have a base class and (e.g.) 10 classes derived from base, the base class has it's own header and cpp, and each derived class has it's own header and cpp file. If another file elsewhere depends only on (e.g.) "DerivedClass07," with #include "DerivedClass07.h," that file need not be recompiled if changes are made to anything but the base class header and "DerivedClass07.h"

I agree with what you're saying here, I guess i'm misreading what you originally said.


Inlining is a hint at best

I wasn't speaking about the inline compiler hint, I was saying that the accessor (example known for trivial size) is so small if inlining is enabled in the compiler will inline it for certain (lets just say this will happen). IIRC inlining can only happen in the same translation unit as you stated cpp file. So if the base class is in a separate cpp file than the child, it is still considered a different translation unit right?

-potential energy is easily made kinetic-

(it's especially in big codebases where it starts to break down and doesn't work well anymore).

What starts to breakdown? Inheritance? if so what makes you say that?

A typical example could be having a big tree of inheritance, and then you find out you need a new type of object that has the properties of two types of objects already in the tree. Using multiple inheritance for this is generally discouraged. That means a re-organization of the tree is needed. If pressed for time, there is risk this re-organization isn't done, which can lead to ugly dependencies and special work-around that are difficult to maintain and debug.

One design pattern that can help in this situation is the Entity-Component-System.

[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

This topic is closed to new replies.

Advertisement