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 ":-)"