Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!utgpu!water!watmath!clyde!cbosgd!ihnp4!drutx!druhi!weh
From: weh@druhi.UUCP
Newsgroups: comp.lang.c++
Subject: Re: Questions about C++
Message-ID: <2010@druhi.ATT.COM>
Date: Fri, 10-Jul-87 12:02:46 EDT
Article-I.D.: druhi.2010
Posted: Fri Jul 10 12:02:46 1987
Date-Received: Sun, 12-Jul-87 11:25:32 EDT
References: <227@nih-csl.UUCP> <134@otc.OZ> <2002@druhi.ATT.COM> <229@nih-csl.UUCP>
Distribution: comp
Organization: AT&T, Denver, CO
Lines: 119
Summary: can STILL use +e option with derived classes

In article <229@nih-csl.UUCP>, keith@nih-csl.UUCP (keith gorlen) writes:
> In article <2002@druhi.ATT.COM>, weh@druhi.ATT.COM (HopkinsWE) writes:
> > A simple approach to using the +e option is to use +e0 (only include
> > external reference to virtual table) for all .c files, and compile
> > the .h files containing the class declarations using +e1 (generate
> > globally accessible virtual tables).
> 
> This won't work on my .h files -- I usually have derived classes.  For
> example, suppose you have a base class B with virtual functions
> declared in the file B.h and classes D1 and D2 derived from B declared
> in files D1.h and D2.h, respectively.  Now to compile D1.h or D2.h,
> you must include the declaration of their base class B, so you might
> as well #include "B.h" in D1.h and D2.h.  So if you compile both D1.h
> and D2.h with the +e1 option both D1.o and D2.o have global
> definitions of the vtbl for class B.  Have I misunderstood something?

Keith's observation is correct. The simplistic solution I suggested
is fatally flawed; there is no point in using the +e option WITHOUT
iheritance and virtual member functions. After some thought, writing
a test case, and consultation with other C++ developers, a reasonable
solution does exist. In summary, a special .c file is used to include
ALL class declarations which needs a virtual table. That file is
compiled using +e1 while all the other .c files are compiled
using +e0. The following example illustrates this:

// base.h
#ifndef base_h
#define base_h

class base {
	int one_int;
public:
	base () { one_int = 0; }
	virtual int get_one_int () { return one_int; }
};

#endif

// derived.h
#ifndef derived_h
#define derived_h

#include 
#include "base.h"

class derived: public base
{
	int one_int;
public:
	derived () { one_int = 1; }
	int get_one_int () { return one_int; }
	void display () { printf("derived::one_int = %d, base::one_int = %d\n",
			get_one_int (), base::get_one_int ()); }

};

#endif

// derived_2.h
#ifndef derived_2_h
#define derived_2_h

#include 
#include "base.h"

class derived_2: public base
{
	int one_int;
public:
	derived_2 () { one_int = 2; }
	int get_one_int () { return one_int; }
	void display () { printf("derived_2::one_int = %d, base::one_int = %d\n",
			get_one_int (), base::get_one_int ()); }

};

#endif

// defs.c
#include "base.h"
#include "derived.h"
#include "derived_2.h"

// main.c
#include "derived.h"
#include "derived_2.h"

main()
{
	derived one_obj;
	derived_2 one_obj_2;
	one_obj.display();
	one_obj_2.display();
}


This compiled using the following commands:

CC +e1 -c defs.c
CC +e0 main.c defs.o

And executes with the expected results:

$ a.out
derived::one_int = 1, base::one_int = 0
derived_2::one_int = 2, base::one_int = 0


The #ifndefs are necessary to ensure that each class is included
once (not a bad practice to follow in general). This approach
has been used in some medium sized projects, and the problem
experienced is that the preprocessor and compiler tables are
stressed.

				Bill Hopkins
				AT&T
				11900 N. Pecos St.
				Denver, CO 80234
				{allegra|ihnp4}!druhi!weh