To have a private base class for the purpose of factoring out code common to
various constructors is fine. However, that is an implementation detail and
by no means indicates that such a private base class for big_float should
be a big_int (even if in a first draft of the class all the code factored
out pertains to the integer part of the big_float). You loose flexibility
if you insist that this base class has a prescribed behavior.
Moreover, if those init functions deal with the integer part only, then
having a big_int member would take care of factoring them out, too: the
big_int member has a constructor and that constructor is called when the
member is initialized. The init-code for the integer part just goes there
and disappears from the big_float class.
Well, what would be a suitable "base" class then for the
big integer part, though? There's really nothing to that
except a length field plus the digits, the latter of which
is held in an object of type std::vector.
Scrapping the inheritance method and replacing it with
using a raw integer object inside the big floating point,
I'd then have this: "BigFloat" contains objects of types
"RawInt" and "SignExp", while "RawInt" contains an object
of type std::vector. The array allocation, etc. that would've
otherwise been handled by Init functions is then handled
by the functions in std::vector, then the assignment and
preparation of the raw integers is handled by their own
constructors, and "SignExp"'s (the sign/exponent combination
wrapped up into a little class all it's own so that
exponent overflow/underflow checking code is made reusable)
constructors handle the preparation of the floating point
number's sign/exponent, with the floating point class's own
constructors finally finishing off the remaining work (for
example if one requests a BigFloat preinitialized to a
specific value, the setting of that value would be achieved
by those constructors).
Private inheritance buys you nothing in this regard. The only effect that
inheritance has compared to composition is the handling of member
functions: with composition you write
integer_part.add ( other.integer_part );
and with inheritance you write
add( other.integer_part );
or (in case of a name-clash, which is not too unlikely given that both
classes are numbers)
my_integer_base::add( other.integer_part );
Of course, as soon as operator overloading enters the picture, the
name-collision problem can become a real hassle.
Yes. Like right now, with the inheritance-based system,
I have two "add" routines inside a BigFloat object: one
"rawAdd" and the other just "Add", the former of which
is private and is used to operate on the digits of the
mantissas, and the latter of which is public and can
be used to do the floating-point arithmetic (there will
also be a special, but public, "FastAdd" routine that is
used for the calculation-intensive parts of the program
and that requires all inputs/outputs to be stored at equal
precision, which allows for some stops to be pulled out).
Which is important, as I have not yet decided on the
licensing model for the software if I actually release it.
The best way to avoid copyright trouble is to make all your
work original, so you own it all.
From experience, I predict that you will a hard time coming close even
within an order of magnitude (if not two). However, it is a fun experience.
So by all means, go for it (if you have the time).
Well, I like doing it.