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.