[net.lang] C++ help needed

ee178acb@sdcc7.UUCP (DARIN JOHNSON) (11/26/85)

A need a few answers to some C++ questions.  But first, a bug.
This code does not compile.  Moving class inner outside of class outer
will cause the thing to compile normally.

  class outer {
    class inner {
      int inner_data;
    };
    int outer_data;
  public:
    int inner_val(inner*);
  };

  int outer.inner_val(inner *x) {
    return x->inner_data;
  };

  I want to implement various forms of trees without letting the
application module know what type of trees they are.  This means
that the same header file should be the interface for all
implementations.  Distance fields should be invisible, as well as
whether binary, or B+ trees are used.  Is there a way to do this?
My solution was to use a #ifdef which to me is a hack.  Is there a
nice way to do this with a modula-2 type of interface?  In c, I did
this sort of thing simulating an Ada "private" type by having a
create function pass back a pointer to a structure, but the
application module thought this was a pointer to a char, int, or
whatever.  Is this type of thing do-able in C++  without using
"pure" c, but using the data-abstraction available?

  Also, when trying to do this sort of thing, I ran across the
problem of friend functions that I don't want the user to know
about.  For example, a merge function that the member functions
call, but which should be private to everyone else.  Is there a way
to do this?  

  C++ is a good improvement on many of c's limitations, but separate
compilation has a ways to go before is can place itself next to Ada
or modula-2, etc.

  Darin Johnson
  trying to figure it out before the students complain.
  sdcsvax!beowulf!wbreader

jes@ulysses.UUCP (Jonathan Shopiro) (12/01/85)

Subject: Re: C++ help needed
Newsgroups: net.lang
References: <188@sdcc7.UUCP>

> I need a few answers to some C++ questions.  But first, a bug.
> This code does not compile.  Moving class inner outside of class outer
> will cause the thing to compile normally.
> 
>   class outer {
>     class inner {
>       int inner_data;
>     };
>     int outer_data;
>   public:
>     int inner_val(inner*);
>   };
> 
>   int outer::inner_val(inner *x) {	// :: was .
>     return x->inner_data;
>   };

This is not a bug.  Nested class declarations are not in the language.
(But note that an object of one class can be a member of another
class).  Even if they were in the language, this code would still be
wrong, because inner_data is a private member of class inner, and so
can only be accessed by member functions of class inner.  The function
outer::inner_val(inner*) is a member function of class outer.  This bug
illustrates the reason why nested classes were removed;  the extra data
hiding they might allow was not considered worth the added complexity
in the compiler and the language definition.

>   I want to implement various forms of trees without letting the
> application module know what type of trees they are.  This means
> that the same header file should be the interface for all
> implementations.  Distance fields should be invisible, as well as
> whether binary, or B+ trees are used.  Is there a way to do this?
> My solution was to use a #ifdef which to me is a hack.  Is there a
> nice way to do this with a modula-2 type of interface?  In c, I did
> this sort of thing simulating an Ada "private" type by having a
> create function pass back a pointer to a structure, but the
> application module thought this was a pointer to a char, int, or
> whatever.  Is this type of thing do-able in C++  without using
> "pure" c, but using the data-abstraction available?

TANSTAAFL (there ain't no such thing as a free lunch)

C++ is a dandy language, but there is no magic in it.  Also, C++ is an
extension of C, so certain options are not open.  For example, if you
have a class X, and you declare an automatic variable of type X, the
compiler allocates space for it on the stack.  That means the compiler
has to know the size of objects of type X.  In some other language, you
might call a function that allocates an object of type X in the free
store, and returns a pointer to it, and put the pointer on the stack.
Very well, but that's not C++.  Inline functions can make code much
more efficient, but in order to expand them, the compiler has to know
their definitions, and the internal structure of their classes.  The
only place the compiler can get this information is the class declaration.

You say you want the application program not to know what kind of tree
it is using.  Does that mean that in order to change tree types, you
are only willing to supply a switch at runtime?  Or will you re-link
the object code of the application with a different library for a
different tree type?  Or are you willing to replace some of the header
files and recompile the application source code?  Would you be willing
to change just one line of the application code before recompiling?
Your choice among these possibilities has strong implications on your
choice of implementation techniques.  The issues and options change
again if you suddenly decide you want your program to be able to
manipulate whatever kind of tree is thrown at it, without having to
know the complete catalog of trees.  C++ can handle all of these kinds
of programming problems, but generality usually has some cost in
performance.

Your task is easiest if you are willing to recompile to change tree
types.  Then you might supply a different header file for each tree
type.  Each header file could contain a declaration of class Treenode
(for example) and the public functions for manipulating Treenodes.  The
name Treenode and the public functions would be the same for each type
of tree, but the private data and functions would be different.  If you
want to change tree types by re-linking, you would probably define a
class Tree whose only data member was a pointer to class Treenode, and
whose public functions were the standard interface to trees, and put
all the code for manipulating Trees and Treenodes in the library for
each Tree type.

I could go on but this is not the place for a complete exposition on
programming with abstract data types in C++.  I recommend reading (and
re-reading) the book, and trying a lot of examples.

>   Also, when trying to do this sort of thing, I ran across the
> problem of friend functions that I don't want the user to know
> about.  For example, a merge function that the member functions
> call, but which should be private to everyone else.  Is there a way
> to do this?

Basically your choices are to tell the user not to look at the private
parts of your class definitions, or to put all that stuff in a library
and only hand out object code.  It might be possible to change the
language and compilation environment so that part of the class
declaration was available to the compiler but not to the programmer,
but it's not obvious that the benefits would outweigh the costs.
-- 

		-- Jonathan Shopiro
		   AT&T Bell Laboratories
		   600 Mountain Avenue
		   Murray Hill, NJ 07974
		   (201) 582-4179
		   allegra!ulysses!jes

keith@cecil.UUCP (keith gorlen) (12/01/85)

>> I need a few answers to some C++ questions.  But first, a bug.
>> This code does not compile.  Moving class inner outside of class outer
>> will cause the thing to compile normally.
>> 
>>   class outer {
>>     class inner {
>>       int inner_data;
>>     };
>>     int outer_data;
>>   public:
>>     int inner_val(inner*);
>>   };
>> 
>>   int outer::inner_val(inner *x) {	// :: was .
>>     return x->inner_data;
>>   };

>This is not a bug.  Nested class declarations are not in the language.
>(But note that an object of one class can be a member of another
>class).  Even if they were in the language, this code would still be

From "Differences between C++ Release E and the AT&T C++ Translator,
release 1.0":

	If a class definition appears inside of another class definition,
	the inner class definition is at the same scope as the outer class
	definition.  The following code is now legal:

		class outer {
			class inner {
			/* ... */
			} x;
		};
		inner y;

Thus it would appear that the latest release of C++ does have nested class
definition, but it can't be used as in the first example.

>C++ is a dandy language, but there is no magic in it.  Also, C++ is an
>extension of C, so certain options are not open.  For example, if you
>have a class X, and you declare an automatic variable of type X, the
>compiler allocates space for it on the stack.  That means the compiler
>has to know the size of objects of type X.  In some other language, you
>might call a function that allocates an object of type X in the free
>store, and returns a pointer to it, and put the pointer on the stack.
>Very well, but that's not C++.  Inline functions can make code much

It seems to me that C++ can do both fairly well:

	class X { ... };

	main() {
		X a;		/* a is an object of class X */
		X& b = *new X;	/* b is a reference (pointer) to an object of
				class X allocated in the free store */

The only problem is that you must remember to delete b when you are done
using it.

>Your task is easiest if you are willing to recompile to change tree
>types.  Then you might supply a different header file for each tree
>type.  Each header file could contain a declaration of class Treenode
>(for example) and the public functions for manipulating Treenodes.  The
>name Treenode and the public functions would be the same for each type
>of tree, but the private data and functions would be different.  If you

A variation on this approach which eliminates the need for re-compilation
(at some cost, of course!) is to have the header file for class Treenode
contain the private data that is common to all types of tree nodes and
"dummy" public virtual function declarations.  Specific types of tree nodes
are implemented as derived classes of Treenode and add data specific to the
node type and implementations of the virtual functions.  The header file
for such a derived class need not be included in any program module that
manipulates only the Treenode abstraction.

>>   Also, when trying to do this sort of thing, I ran across the
>> problem of friend functions that I don't want the user to know
>> about.  For example, a merge function that the member functions
>> call, but which should be private to everyone else.  Is there a way
>> to do this?

>Basically your choices are to tell the user not to look at the private
>parts of your class definitions, or to put all that stuff in a library
>and only hand out object code.  It might be possible to change the
>language and compilation environment so that part of the class
>declaration was available to the compiler but not to the programmer,
>but it's not obvious that the benefits would outweigh the costs.

Another possible solution to this type of problem in C++ is to implement the
merge function as a private member function of a class, then declare the
classes/functions to be permitted to call it as friends.  The big disadvantage
of this is that adding a new class requires adding its name to the list of
friends and re-compilation of everything that uses the class containing the
merge function.

Personally, I don't object to clients being able to look at the private parts
of a class as long as they can't touch them!

-- 
---
	Keith Gorlen
	Computer Systems Laboratory
	Division of Computer Research and Technology
	National Institutes of Health
	Bethesda, MD 20892
	phone:	(301) 496-5363
	uucp:	{decvax!}seismo!elsie!cecil!keith

tim@ISM780C.UUCP (Tim Smith) (12/05/85)

Hey guys!  This is net.lang.c, not net.lang.c++.  Please keep articles
like this out of net.lang.c.  Use net.lang.  If there are a lot of c++
articles, then try to get net.lang.c++ created.

					Tim Smith
					ima!ism780!tim
					ihnp4!cithep!tim
ps: Take this posting with a large ":-)"