[comp.lang.c++] C++ Static Members and Inheritance

whisd@sersun1.essex.ac.uk (Whiteside S D B) (04/30/91)

I noticed something in some classes I was producing using Borland C++ recently.

It seems anomalous, can anyone let me know of what they think:

I had a base class in which I declared a static data member.

I then derived TWO separate classes which both inherited from the base class.

Then these classes were instanstiated as objects I found that for BOTH the static data member (a pointer) had the SAME value.

Now I know that a static member is the same for every object of a class, but is the same for every object of a DERIVED class?

My two objects were not of class "base" but of classes "derived1" and "derived2" respectively.

I expected each object of Derived1 to have the same data member inherited from base class, and likewise for Derived2, but not that all objects of BOTH classes would have the same.

I've searched literature high and low for an answer to this. Nowhere do they mention what happens when you inherit a static member (data or function).

Any suggestions or corrections welcome.

Simon Whiteside
 

landauer@morocco.Eng.Sun.COM (@morocco.eng [Doug Landauer]) (05/01/91)

> Now I know that a static member is the same for every object of a class,
> but is the same for every object of a DERIVED class?  My two objects were
> not of class "base" but of classes "derived1" and "derived2" respectively.

The whole point of inheritance (public inheritance, at least) is that
the derived "is a" base, so that you can use the derived object as if
it were a base object.  The static member is shared among all instances
(objects) of the base class, including the embedded "base" object that
lives inside each derived object.

> I've searched literature high and low for an answer to this.  Nowhere do
> they mention what happens when you inherit a static member (data or
> function).

Yeah, I think you're right -- I can't find a particularly explicit mention
either of this particular issue (inheritance vs static members), or of the
general principle that a derived "is a" base.  Perhaps X3J16's editor could 
add a sentence or two to make these things more clear.  Here's the things
I found that came closest to these issues:

    E&S, Section 9.4:
	There is only one copy of a static data member, shared by
	all objects of the class in a program.

    E&S, Section 10:
	A derived class can itself serve as a base class ...

    E&S, Section 11.2:
	Specifying a base class "private" does not affect access to
	static members of the base class.

    (Note that the latter has been rewritten a bit in the current draft --
    it says something more like
	Because of the rules on pointer conversion (section 4.6), a static
	member of a private base class may be inaccessible as an inherited
	name, but accessible directly.
    now.  But remember that it's still just a Draft.)
-- 
Doug Landauer - Sun Microsystems, Inc. - Languages - landauer@eng.sun.com

philip@pescadero.stanford.edu (Philip Machanick) (05/01/91)

In article <5069@servax0.essex.ac.uk> whisd@sersun1.essex.ac.uk (Whiteside S D
B) writes:
>I noticed something in some classes I was producing using Borland C++
recently.
>
>It seems anomalous, can anyone let me know of what they think:
>
>I had a base class in which I declared a static data member.
>
>I then derived TWO separate classes which both inherited from the base class.
>
>Then these classes were instanstiated as objects I found that for BOTH the
static data member (a pointer) had the SAME value.
>
>Now I know that a static member is the same for every object of a class, but
is the same for every object of a DERIVED class?
[...]
>I've searched literature high and low for an answer to this. Nowhere do they
mention what happens when you inherit a static member (data or function).
>
I had exactly the the same problem with AT&T cfront 2.0 last year. On a quick
scan of ARM, I could find no mention of this behaviour, but lots of people
assured me that this is "standard".

Philip Machanick

mr3@ukc.ac.uk (M.Rizzo) (05/06/91)

In article <5069@servax0.essex.ac.uk> whisd@essex.ac.uk (Whiteside S D B) writes:

>I had a base class in which I declared a static data member.
>
>I then derived TWO separate classes which both inherited from the base class.
>
>Then these classes were instanstiated as objects I found that for BOTH the static data member (a pointer) had the SAME value.
>
>Now I know that a static member is the same for every object of a class, but is the same for every object of a DERIVED class?
>
>My two objects were not of class "base" but of classes "derived1" and "derived2" respectively.
>
>I expected each object of Derived1 to have the same data member inherited from base class, and likewise for Derived2, but not that all objects of BOTH classes would have the same.
>
>I've searched literature high and low for an answer to this. Nowhere do they mention what happens when you inherit a static member (data or function).
>
>Any suggestions or corrections welcome.

I've experienced this problem before.

The only solution I found was to re-declare the static data members
in every subclass I needed them.  However this should be done with
care. If a base class member function refers to a static data member,
then if this function is inherited by a derived class re-declaring the
same static member, the base class static member will still be the one
referenced by the inherited function.

What we need here is virtual static data members !  Unfortunately there
are no such thingies :-(

To solve this problem you can define two virtual non-static functions
to read and write the member - though again this must be done for
every derived class where the static member is declared. Macros are very
handy here !

Does anybody know of another (possibly better) approach ?  Also, a
suggestion - why not consider adding virtual static data members
to the language defintion ?  (No I haven't got it wrong - I know
``virtual'' is normally associated with functions)  I think they
could be useful as described in the above case. The need to
have derived classes with _their own_ static data often arises
e.g. to store an instance count.

>Simon Whiteside

Michael Rizzo

philip@pescadero.stanford.edu (Philip Machanick) (05/06/91)

In article <7510@harrier.ukc.ac.uk> mr3@ukc.ac.uk (M.Rizzo) writes:
>In article <5069@servax0.essex.ac.uk> whisd@essex.ac.uk (Whiteside S D B)
writes:
>
>>I had a base class in which I declared a static data member.
>>
>>I then derived TWO separate classes which both inherited from the base class.
>>
>>Then these classes were instanstiated as objects I found that for BOTH the
static data member (a pointer) had the SAME value.
[...]
>The only solution I found was to re-declare the static data members
>in every subclass I needed them.  However this should be done with
>care. If a base class member function refers to a static data member,
>then if this function is inherited by a derived class re-declaring the
>same static member, the base class static member will still be the one
>referenced by the inherited function.
>
>What we need here is virtual static data members !  Unfortunately there
>are no such thingies :-(
>
>To solve this problem you can define two virtual non-static functions
>to read and write the member - though again this must be done for
>every derived class where the static member is declared. Macros are very
>handy here !
>
>Does anybody know of another (possibly better) approach ?
[...]
Make the statics private (rather than protected). Then you are forced to
redeclare them for derived classes. This still doesn't help you if you call a
function higher up the hierarchy - the only solution I can propose here is that
you pass the statics as parameters at all times. This, combined with the use of
private, ensures you get the right one.

Again - a better approach would be appreciated.

Philip Machanick

daves@ex.heurikon.com (Dave Scidmore) (05/08/91)

whisd@essex.ac.uk (Whiteside S D B) writes:
>I had a base class in which I declared a static data member.
>I then derived TWO separate classes which both inherited from the base class.
>Then these classes were instanstiated as objects I found that for BOTH the
>static data member (a pointer) had the SAME value.

philip@pescadero.stanford.edu (Philip Machanick) writes:
>Make the statics private (rather than protected). Then you are forced to
>redeclare them for derived classes. This still doesn't help you if you call a
>function higher up the hierarchy - the only solution I can propose here is that
>you pass the statics as parameters at all times. This, combined with the use of
>private, ensures you get the right one.

Perhaps I am dense, but I would assume that if a static member variable
was declared in a base class it is because you want only one instance of
that variable to exist for that class and all those derived from it. I
am having trouble envisioning a situation where you would want multiple
static member variable (a contradiction in terms IMHO). It seems to me
that if you want separate static member variables in derived classes you
would declare them there. This problem seems somewhat analogous to the
case where you want all objects of a class to be "attached" to some
set of possible static variables though not all to the same variable.

For example I have created an error handler classes to deal with all the
different types of errors one particular program can have. In the case of
internal errors the program may exit immediately. So do file I/O
errors, but they always print a file I/O location. Up to 'n' compilation
errors can occur before exiting, and some error messages are just warnings
and do not exit at all. The solution was to create groups or classes of
error handlers and attach each error handler to the appropriate class of
error handler. This is done by requiring a pointer to the error handler
class class when constructing an error handler.

Would it be practical in your situation to force construction of each
base class to include a pointer to a static member variable which it
uses in place of a permanent static member variable. Classes derived from
the base class can then provide their own static member variable and
construct the base class using that variable. Just a thought.

If having the base class store a pointer to a "static" variable represents
too much overhead then perhaps requiring base class method invoctions to
provide a pointer to the derived class static member variable would work.
--
Dave Scidmore, Heurikon Corp.
dave.scidmore@heurikon.com

noren@dinl.uucp (Charles Noren) (05/10/91)

In article <520@heurikon.heurikon.com> daves@ex.heurikon.com (Dave Scidmore) writes:
>
>Perhaps I am dense, but I would assume that if a static member variable
>was declared in a base class it is because you want only one instance of
>that variable to exist for that class and all those derived from it. I
>am having trouble envisioning a situation where you would want multiple
>static member variable (a contradiction in terms IMHO).

There are cases where you may want multiple instances of
static members of the same name.  One example of use is
in the NIH Class Library (NIHCL). A good description of its
use is found in the book DATA ABSTRACTION AND OBJECT-
ORIENTED PROGRAMMING IN C++, by Gorlen, Orlow, Plexico
(1990, John Wiley & Sons, ISBN 0-471-92346-X), pp 144-146.
In NIHCL, the static member classDesc is defined for each
class, and you must define it for each class you derive from
another NIHCL class (this is done for you in their DECLARE_MEMBERS
and DEFINE_CLASS macros).  The classDesc member is an instance of
NIHCL's Class class which keeps certain information specific to
the class it is defined in.  Its address is also used to identify
what class an object belongs to.  For instance, every class
implements the member function isA usually as:

   const Class* X::isA() const {return &classDesc;}

Again, this is provided for the NIHCL applications user inside
the macro DEFINE_CLASS.  Certainly there are other ways of
providing class identification, but this gives a flavor of what
can be done by "overloading" a static member with another of the
same name.

BTW, using this mechanism inside NIHCL's castdown functions
also provides a safe mechanism for doing "down casting" of
object pointer from classes with virtual base objects
(described on pp. 325-328 of DATA ABSTRACTION).

-- 
Chuck Noren
NET:     dinl!noren@ncar.ucar.edu
US-MAIL: Martin Marietta I&CS, MS XL8058, P.O. Box 1260,
         Denver, CO 80201-1260
Phone:   (303) 977-1646