inheritance overkill?

Started by
9 comments, last by GenuineXP 15 years, 3 months ago
Hello, I am trying to determine wether or not i should use inheritence. I am coding a molecule class (C++) which owns a few instances of an atom class. Atoms come in many types (114 to be precise: carbon, hydrogen, nitrogen, etc.) and each has its own properties (weight, valence,...) . They behave quite similar however and if i would derive each of them from a base atom class, i would (for the time being) need only one virtual method to check for errors in user input. So which is better:

class atom{
virtual bool checkcorrectness();
};

class carbon::public atom{
virtual bool checkcorrectness();
}

class nitrogen::public atom{
virtual bool checkcorrectness();
}

or


enum atomtype{carbon, nitrogen};

class atom{
atomtype itstype;
bool checkcorrectness(){if itstype=carbon "do this" else "do something else"};
};

? for now, the second one seems more convenient, but it could be that later on, more member functions will behave differently depending on the atom's type. 114 derived classes just seems to much to me...
Advertisement
114 derived classes seems too much but 114 enum types and if statements doesn't?
It's not a bug... it's a feature!
Quote:Original post by twoaterisn

Atoms come in many types (114 to be precise: carbon, hydrogen, nitrogen, etc.) and each has its own properties (weight, valence,...).


This is a definite case for *not* using inheritance. An atom is an atom. Just because Hydrogen atom has different weight from carbon it doesn't make it something else.

I blame this on nonsensical OO tutorials, which use Pizza, PizzaWithCheese, PizzaWithHam, PizzaWith... examples to illustrate inheritance. A pizza is a pizza. There is only one. Just because it has different toppings it doesn't make it something else.

Quote:for now, the second one seems more convenient, but it could be that later on, more member functions will behave differently depending on the atom's type. 114 derived classes just seems to much to me...


There's a problem with your abstraction. There is nothing in periodic table of elements that would require one element to be treated differently from another. All atoms are equivalent.

They have different composition, but they are still the same.

And if you use virtual function, there already is an enum. It's called vtable, which determines which function to call. Using enum manually in combination with switch or if statement does precisely and exactly what polymorphism does, and is how polymorphic functions are sometimes implemented in non-OO languages.

Quote:i would (for the time being) need only one virtual method to check for errors in user input.


You only need one function total. What exactly is this method supposed to do?
Isn't there a general way to describe the valid data input for all 114 types with a few parameters?
If they are really so similar, that is probably possible. Place these in a file or look up table and you can skip your whole inheritance/if statement overkill.

Dietger
Hm, what exactly is different about the behavior of the different elements (not the data, like mass, but the behavior)? If there isn't a difference, subclassing probably isn't necessary at all. If there is, is it solely determined by the data? If so, why can't external objects just read the data and determine the proper course of action?

One example of this situation I've seen on these forums before is an RPG with character classes. Most people instantly code a base class from which they derive different game classes (bard, warrior, mage, etc.). However, this is often viewed as an abuse of inheritance, since the data (i.e., stats) may be different, but the behavior is essentially the same.

Also, I'm assuming that the data for each atom is static and does not change at runtime (this makes sense, unless you're planning on simulating electrons, nuclear reactions, ions and electricity, or some other phenomenon that can alter the state of the atom). In this case, you may want to look into template meta-programming. Using class/struct templates could speed up your code and allow you to do some neat tricks and optimizations. This would probably require a large enumeration though, and could easily lead to code bloat.

enum elements {    hydrogen,    helium};template<elements E>struct atom { BOOST_STATIC_ASSERT(0 == sizeof(E)); };template<>struct atom<hydrogen> {    enum { some_int_data = 0 };    static const float some_float_data = 0.0f;};template<>struct atom<helium> {    enum { some_int_data = 0 };    static const float some_float_data = 0.0f;};template<element E>void foo(const atom<E>& bar) {    std::cout << bar.some_int_data << std::endl;}


Just an idea. Anyway, I hope something here helps. :-) Good luck!

[Edited by - GenuineXP on January 16, 2009 10:42:09 AM]
Just have an element class with name, symbol, protons, neutrons, electrons, etc.

Then if you want to get fancy make a set of enums for the common elements and a factory (or a simple constructed std::map) to give you the constructed element object for an enum.

One thing to remember/consider is that there's like 4 different isotopes of carbon, so 'just' carbon is perhaps inadequate. That's also a pretty good motivator to allow construction of elements outside of the factory/map.


Realistically, methods in element shouldn't change based on the 'type' of the atom. What methods would you have? I can't think of anything that couldn't be better done just with data on the type.
By external objects reading the data, do you mean that i should move the checkcorrectness() outside the atom class? wouldn't this be C-style programming or is it just that i don't get what you're saying? :)

like this:

class atom{};
bool correct (atom* givenatom);

PS I'm a chemist by education so forgive my ignorance on C++ and my tendency to treat hydrogens differently from carbons, lol.
Although not knowing the exact use case, I would throw in the following variant (please ignore any chemical nonsense, because school is out for some years now ;) ):

A class Element is responsible to describe the atoms of a specific element. The corresponding data are the number of electrons/protons, the standard number of neutrons and perhaps a range to describe known isotopes, the name (for sure), the abbreviated name, ... whatever is constant for all atoms of that element. Then for each element of interest an instance is instanciated using the correct data, of cause. The instances may be stored in maps using the name/abbreviated name or whatever as key, and/or in an array using the

Then a class Atom can be used to define the actual usage of an Element, e.g. as part of a Molecule instance. So Atom becomes a lightweight, because the majority of data is out-sourced. What remains is a pointer to the correct Element instance as well as any instance data, e.g. perhaps the actual amount of neutrons to better deal with isotopes.
Also a molecule consists of several atoms so you should better let it store a vector of atoms.
Then you can also easily perform reactions by passing atoms from one molekul to another etc
My Blog - http://www.freakybytes.org
Quote:Original post by twoaterisn
By external objects reading the data, do you mean that i should move the checkcorrectness() outside the atom class?


What does checkcorrectness() need to do? Can you show how you would implementat it for H, C and Si?

This topic is closed to new replies.

Advertisement