C/C++ Contributing Editors


Uncaught Exceptions: All Good Things

Bobby Schmidt

Some words of wisdom for the departing editor, and — as usual — some priceless C/C++ info for readers.


Copyright © 2001 Robert H. Schmidt

...and then there was one.

Marc Briand has left the building. In exodus he follows Pete Becker, Dan Saks, and P.J. Plauger: all regular monthly writers on board when I started (November 1995 issue), but gone now. I suddenly find myself high in seniority and a tad lonely.

I’m going to miss Marc. I always enjoyed doing time with him at trade shows and conferences; but in his new life, I somehow doubt he’ll have much occasion to attend them anymore. And we never (well, almost never) had disagreements about editorial tone and direction. I hope I won’t have trouble training, er, “working with” his replacement.

This column is my last edited by Marc. As I write, I’m not sure who will be topping the masthead next. Someone close to the magazine (not Marc) approached me about taking on a larger role; I had to decline, if only because Microsoft is absorbing quite enough of my time.

I understand why Marc’s left. I understand why they’ve all left. Magazine writing is marathon running. The trick is to find a pace that’s fast enough to win, yet slow enough to sustain. Unfortunately no runner can go forever, and eventually we all drop out of the race.

It lurks in the future mist, quietly waiting: that first day I don’t write anymore. I’m in no hurry to find it. After all these years, the thrill of seeing my words published hasn’t faded. And every time readers tell me they rip open their new issues and plunge straight to my column first — my column! — I’m reminded of why I entered the race [1].

So Marc, I dedicate this column to you. Until we meet again, may you always get your six perfect weeks of Kansas weather, late-spring skies filled with chase-worthy storms. May you finally wake up, look in the mirror, and realize that the ’70s are like so over dude. May you laugh with — and not at — the next editor fool enough to roundup compiler conformance. And may you finally scrape up the courage to ghostwrite Sanford D’s memoirs.

“Turn out the lights, the party’s over. They say that all good things must end...”

Virtual Reality

Q

The code that follows produces (on a Solaris box) the following output when the function f is virtual in A:

ffbef9a0
B::f

ffbef9a0
B::f

Furthermore, it produces the following output when the function f is non-virtual in A:

ffbef9a3
B::f

ffbef9a3
A::f

This result is very confusing to me because in each case we merely have an object of type B — namely b.

It would seem to me that since each of our calls involve an object — not a pointer — of type B, in all cases the B::f method should be invoked. I have added the revelation of the this pointer just to show that indeed we are looking at the same object.

Obviously my reasoning is in error, and I am overlooking something. Could you please explain why the b object invokes the A::f method even though it has inherited the A::do_f method? In other words, please explain the mechanism by which this result is taking place.

Thanks — Phil Couchara

A

All four results you report are correct.

The first version of your program, with f virtual, appears as Listing 1. That program shows two calls to f: one direct, one indirect (via do_f):

Now change your program so that f is non-virtual. This new program shows the same two calls to f. But because f is non-virtual, there is no run-time vtable to resolve calls to f. Instead the compiler reckons which f to call based on static-type context.

The compiler reaches its conclusions thusly:

In both cases, f resolves based on the static context of the caller. The actual run-time type of the calling object is irrelevant, as no virtual dispatch is involved or even possible.

Bottom line:

Chain Letter

Q

Hello Bobby,

My name is Mohammed, and I am a const reader of the CUJ, and especially the Q&A part. Great job! I extend my greeting to you and your friends making this publication available to us C++ users.

I am not an experienced C++ developer, but I am making the effort to be. I have some questions about C++ and thus am writing to you.

Question 1: When overloading the operators << and >> to support I/O on our own classes, why do we return a reference to istream and ostream?

Question 2: Why do we return a reference to this when overriding the assignment operator?

I know you may say “consult a C++ book like ...,” and I did read some books, but I still did not get a clear idea about my questions.

Thanks very much — Mohammed Abu Hajjleh

A

My first “const” reader — Dan Saks will be proud!

The answer to both questions is quite simple: by returning these references, the operations can be chained together:

X a, b, c;
a = b = c;
cout << a << b << c;
cint >> a >> b >> c;

I’ll explain the case of assignment first and generalize from there.

The statement

a = b = c;

groups as if it were written

a = (b = c);

Assuming X is a class type above, and assuming operator= is the typical self-assignment declared as

X &operator=(X const &)

then the chained expression is really the nested function call

a.operator=( b.operator=(c) );

The inner call

b.operator=(c)

takes c as its argument. c has type X, which converts nicely to the operator= parameter type X const &. No drama there.

The outer call

a.operator=( b.operator(c) );

takes the result of b.operator(c) as its argument. Because operator= has a return type of X &, the result of b.operator(c) is an X &. That X & result converts to the X const & parameter type a.operator= requires.

In sum: by being declared to return the same type it accepts, operator= can form chained calls to itself.

All of this implies that b.operator= returns a reference to some X object — but which one?

Remember that

a = b = c

sets the state of b from c before setting the state of a from b. The X returned by b.operator= is therefore the state of b after it’s been set. Implication: b.operator= returns b, which is conveniently available in operator= as *this and is yielded via return *this.

And that’s the story of why operator= returns *this.

Counter-argument: The entire expression a = b = c eventually returns a. That value is not further chained, but is silently tossed away. If you never intend to chain assignment this way, declare operator= to return void, thereby sparing the overhead of wasted return values.

This same basic reasoning applies to << and >>, except the associativity is in the other direction, and the operators are very frequently chained. For example, the sequence

cout << a << b;

is tantamount to

(cout << a) << b;

where << is a call to operator<<. Depending on the types of a and b, the operator<< call is either a member of cout with one parameter:

( cout.operator<<(a) ).operator<<(b);

or a non-member function with two parameters:

operator<<( operator<<(cout, a), b);

In the former case, operator<< returns *this, which is the stream cout. In the latter case, operator<< returns its first parameter, which is also the stream cout. Both net out to the same effect: each operator<< result is passed down the chain to the next call, as either the value of *this or the first argument.

Oh Say Can You C?

Q

Bobby,

Can you please tell me if there is a mechanism that allows ANSI C programs to access/call functions that have been compiled in C++ modules or libraries. I know that the reverse is possible using the extern "C" declaration.

I have an immediate need to access a “C-like” API that is only available as C++ generated libraries. The project that I am working on consists of a slew of ANSI C modules that will not compile/run correctly as C++ code without a significant amount of rework.

Regards — Nabil Dajani

A

Because you’re asking about C calling into some other language’s library, the question falls under the jurisdiction of the C Standard.

The only specific library the Standard governs is the Standard C library. The Standard tolerates other libraries and externally-linked entities that follow the C language rules. In all cases, the Standard specifies only the observable behavior of external code. The actual code implementation could be written in any language.

That’s the theory. In practice, every C compiler has its own implementation peculiarities. Your prebuilt C++ library may be callable from one C compiler and not from another. As the C++ Standard puts it [2]:

Linkage from C++ to objects defined in other languages and to objects defined in C++ from other languages is implementation-defined and language-dependent. Only where the object layout strategies of two language implementations are similar enough can such linkage be achieved.

There are so many considerations that I can name but a few:

If you can’t answer these and similar questions, you’re probably out of luck.

But if you can answer the questions, there is hope: you can write a thin layer of new code that maps the C++-specific behavior of the library into a C-compatible form. You declare functions in this layer extern "C" and call them from your C code as if they were C.

While I could literally write an entire book on this topic, you’ll have to settle for the tiny example I show in Listing 2. The example won’t build; it’s meant for demonstration purposes only. It is also quite limited. In real life, the layer will probably require a combination of C++ and assembly language.

(By the way, the example shows a mangled C++ name. That name is the one produced by Metrowerks CodeWarrior Pro 6, although the idea and issue apply to other compilers.)

Simple Simon

Q

Simple question: In 2001, is there any reason to use C over C++?

Thanks in advance — M. Thomas Kent

A

Simple answer: yes.

More complex answer: yes, if you

Most “yes” answers are based on business practicality. If you discount those considerations, and ask the question based on language design and ability only, the answer is almost always “no.”

Notes

[1] Getting free press passes to conferences and trade shows, with all the perks they entail, isn’t a bad motivation either. The only real drag comes at shows with press-averse sponsors and attendees. My worst experience, ironically enough, came at a Microsoft-sponsored conference. When I wore my distinct red press badge, the good people of Redmond shunned me like Hester Prynne.

[2] Subclause 7.5/9.

Although Bobby Schmidt makes most of his living as a writer and content strategist for the Microsoft Developer Network (MSDN), he runs only Apple Macintoshes at home. In previous career incarnations, Bobby has been a pool hall operator, radio DJ, private investigator, and astronomer. You may summon him on the Internet via BobbySchmidt@mac.com.