bs@alice.UucP (Bjarne Stroustrup) (07/08/86)
Release 1.1 of the C++ translator is now being shipped. As promised, 1.1 primarily represents a quality improvement over release 1.0 and provides no major language extensions. It is, of course, compatible. 1.1 runs faster, uses less memory, generates better code, has fewer ``sorry not implemented'' messages, detects more errors, gives better error messages, is more portable, and has fewer bugs than 1.0. The performance improvements are measurable but not dramatic. The ``language recognition and error handling'' quality improvements are noticeable. Almost all bugs reported on the net, to me, or to AT&T as of June 1 are fixed. Internally, the most extensive changes are the handling constructors of the form X(X&), handling of destructors, handling of pointer to functions, handling of ``const'', error and ambiguity detection for overloaded functions, memory allocation (1.1 uses malloc, not break), and some aspects of error handling. 1.1 does provide two language extensions: - pointers to members - protected members I don't consider them major, but for some styles of programming they are significant. The problems these extensions are designed to cope with have been known for years, but only recently did I find suitable solutions. I'm trying to keep C++ an evolving language without getting into incompatibilities or creeping featurism. This is not easy. The two new features are documented in the 1.1 release notes. As far as I know, the price of 1.1 is the same as for 1.0 ($250 for educational institutions and $2000 for commercial firms for source). If you already have a commercial license for 1.0 you get 1.1 for $400. The PC versions of C++ sold by Oasys are based on Release 1.1. As usual, the translator comes for AT&T 3Bs or VAXs running SysV or BSD. Release 1.1 includes a ``porting kit''. It is easier to port than 1.0. There is a new compiler option: +e. ``CC +e1'' causes virtual tables to be external and defined (that is, initialized). ``CC +e0'' causes virtual tables to be external and only declared (that is, uninitialized). ``CC'' causes virtual tables to be local to a file (static) and defined (as always in 1.0). Using +e you can optimize a program by ensuring that only one virtual table per class is generated. This can save 25% of .o size, a.out size, link time, and (in case of cross compilation) download time. If you don't use it everything remains as it was with 1.0: +e is a pure optimization. Pointers to Members: As mentioned in the C++ book (page 153) there was no proper way of declaring and using pointers to member functions. This has been fixed (and the word ``Sorry'' was removed in the second printing). Consider: struct s { // ... int mf(char*); }; How do you declare a pointer to a member function such as ``s::mf''? How do you call a function through such a pointer? A pointer to member function is declared just like any other pointer to function except that it must be explicitly stated that the pointer is to a member of a specific class. ``s::*'' means ``pointer to member of class s''. For example: int (s::*pmf)(char*) = &s::mf; Since ``pmf'' points to a member function and since a member function must be called for a specific object an object must be supplied in a call (in addition arguments required by the member function): s obj; int i = (obj.*pmf)("some string"); s* p = &obj; i = (p->*pmf)("another string"); The parentheses around the .* and ->* expressions are necessary because of the standard C++ operator binding rules i = p->*pmf("another string"); means i = p->*(pmf("another string")); and that is an error. It is possible to take the address of a virtual function and assign it to a pointer to member function. In that case the actual function is found at the time of each call through the pointer dependent on the object it is called for. struct b { virtual void f() { printf("base"); } }; void (b::* pvf)() = &b::f; struct d : b { void f() { printf("derived"); } }; d a; b* p = &a; main() { (p->*pvf)(); } Will print ``derived'' (not ``base''). Protected Members: The basic scheme for separating the (public) user interface from the (private) implementation details has worked out very well for data abstraction uses of C++. It matches the idea that a type is a black box. It has proven to be less than ideal for object-oriented uses. The problem is that a class defined to be part of a class hierarchy is not simply a black box. It is often primarily a building block for the design of other classes. In this case the simple binary choice public/private can be constraining. A third alternative is needed: A member should be private as far as functions outside the class hierarchy are concerned but accessible to member functions of a derived class in the same way that it is accessible to members of its own class. Such a member is said to be ``protected''. For example, consider a class ``node'' for some kind of tree: class node { // private stuff protected: node* left; node* right; // more protected stuff public: virtual void print(); // more public stuff }; The pointers ``left'' and ``right'' are inaccessible to the general user but any member function of a class derived from class ``node'' can manipulate the tree without overhead or inconvenience. A related change is that you can now also use ``private'' labels in a class in the same way as you can have ``public'' and ``protected'' labels: struct my_type { // public interface private: // private stuff };
mitch@well.UUCP (Mitchell Waite) (07/11/86)
I understand that this might be a late point to ask this question, but I was wondering if you could elaborate just a bit about what C++ offers over regular C and if you think many C programmers will be moving towards C++. I have not found a single article that really compares the two langauges in a simple way. I hope this is not too much to ask.