RH> please feel free to pick only question(s) that you feel like answering.
Sounds like my professional exam... "Pick 4 of the following 5 questions..."
:-)
RH> If not that, I would also very much welcome an URL for
RH> a copy of the draft ANSI C standard, assuming it also
RH> includes the standard libary functions. I also read the
RH> C_ECHO, and remember a new draft being released? I
You can get the current standard by ordering a copy of the Annotated ANSI C
Standard (ISBN 0-07-881952-0) and ignoring the annotations. Much cheaper
than ordering straight from ANSI or ISO, I hear.
A new draft is in the works - called C9X. (So long as it doesn't end up as
ANSI C '99...) I don't know where to get a hold of it...
RH> Should I allow the compiler to allocate enums as single
RH> bytes? Or to use unsigned characters by default? It
RH> allows me to set these as options, but I believe both
RH> could get me into portability trouble? What's standard?
I don't think any of them make portability a problem unless you intend on
sharing data between your program and another one on the same platform
(another DOS or Windows app, for example). If you intend on sharing data
with other platforms, well, that's another problem entirely.
Another problem arises if you want to share data with a "newer" version of
your own program. For example, in V1, you save data in a binary file. In
V2, you want to read it - even if it is a V1 file. Well, you have to make
sure that the V2 knows how to interpret everything. Don't worry about this
until you get there. (One way to avoid everything is to save your stuff in
ascii...)
RH> When overloading operators for a class, when should I
RH> implement the functions as member functions, and when
RH> as friend functions? My textbook demonstrates both
RH> methods, but doesn't say when nor why to use either.
members when possible, friends otherwise... that's my rule. :-)
For example, if you want to be able to add a foo with an int and end up with
a foo...
class foo
{
friend foo operator+(int, const foo&); // int + foo
public:
foo operator+(int); // foo + int
foo& operator+=(int); // foo += int
};
However, even in this case, the friend isn't needed... just have:
foo operator+(int i, const foo& f)
{ return f + i; }
Another way is:
foo operator+(int i, const foo& f)
{ foo f2(f); return f2 += i; }
And yet another way is:
foo operator+(int i, foo f) // not const nor reference!
{ return f += i; } // we have a local copy of f!
However, this may not work where the operation is not commutative (sp). That
is, where a+b != b+a. Then you would need a friend function.
RH> void X::operator=([const] X&);
[Yuk]
RH> X& X::operator=([const] X&);
[MUCH better! ]
RH> returning "*this", as Borland's online help says I
RH> should do? Is there a difference?
There is a difference. For example:
X a, b, c;
// create c
a = b = c; // only if b.operator=(c) returns a reference to either b or c
Note that this is expanded like the comment says:
a.operator=(b.operator=(c));
Now it's just a function call... if X::operator=(const X&) returned void, you
couldn't do this. Another one, which I highly don't recommend, is:
(b = c).modifyState();
(Whether b's state or c's state is changed is unknown...)
Thus, IMO, the best way is:
const X& X::operator=(const X&);
Now things like:
(b = c).getState(); // getState is a const function, see below
will work, but modifyState won't.
A const function is not allowed to modify any of the member variables and is
declared as:
class foo
{
return_type func(/* parameters or not, as needed */) const;
//^^^^^ important part
};
return_type foo::func(/* ??? */) const
{ //^^^^^ has to be here too
// code
return rc;
}
So, going back a little bit, we could have:
class foo
{
public:
foo operator+(int) const; // we return a different foo, not this one
const foo& operator+(int); // we modify this foo, so it can't be const
};
This const thing is irrespective of parameters - parameters can be const or
not without making the function const.
RH> In an exercise which asked to to overload the ++ and --
RH> prefix and postfix operators for a class, I wrote the
RH> following test code:
RH> cout << "a == " << a.GetValue() << "; ++a == " << ++a << endl
RH> << "a == " << a.GetValue() << "; a++ == " << a++ << endl
RH> << "a == " << a.GetValue() << "; --a == " << --a << endl
RH> << "a == " << a.GetValue() << "; a-- == " << a-- << endl
RH> << "a == " << a.GetValue();
Let's expand this a little bit.
cout.operator<<("a == ").operator<<(a.GetValue()).operator<<("; ++a == ")
.operator<<(++a).operator<<(endl). // etc - you get the idea
So what should happen? Well, first, cout.operator<<("a == ") should be
called. We then take the return from this function (which is an ostream&,
which just happens to also be cout) and use that to call its operator<<()
function. However, we have a major problem.
It's called sequence points.
We have none.
There is no point here that explicitly says "this is where everything needs
to be synced." There are only two such places in C/C++: , and ;.
RH> First I was quite surprised by the really wrong output
RH> this produced but after some minutes of hard thought
RH> (and cursing buggy compilers), I concluded this really
RH> was to be expected as a result of the cdecl (by the
RH> way, is that an acronymn?) right-to-left style of
RH> argument passing.
Nope - anything and EVERYTHING can be expected by this program.
RH> "Due apparently to a bug in Borland C++ 4.5, using that
RH> compiler did not produce the preceding results. If you
RH> experience this problem, repaired in Borland C++ 5, use
RH> the following main function, which divides the
RH> multipart output statements and ensures that the
RH> expressions are evaluated in strict left-to-right
RH> fashion: [ 9 couts]"
There's no bug here. This is due, apparently, to a bug in the author's head
- this is illegal code and is allowed to produce pretty much whatever result
that the compiler feels like on the given day.
RH> Pardon? Bug? Annoying as it is, this behaviour is to be
RH> expected of cdecl isn't it? Furthermore, if it is a
RH> bug, it doesn't seem fixed...
It's undefined behaviour... and the ultimate undefined behaviour is to format
your hard drive. Don't do it. ;-) ALWAYS use sequence points when you want
to modify a variable twice.
a = ++a + 2; // ILLEGAL! Modifying 'a' twice (operator++ and operator=)!
==========
++a;
a = a + 2; // much better. (Now change it to a += 2)
==========
a += 3; // even better. ;-)
RH> I guess this is a Borland specific question, but is
RH> there any way to stop name mangling for class member
RH> functions? I know that normally, when implementing
RH> functions in an external assembly language module I can
RH> declare them as extern "C" to stop name mangling, but
RH> the compiler doesn't seem to let me do that with member
RH> functions.
Right - because you can have multiple ones with the same name.
class foo
{
foo(int);
foo();
foo(char, char* = NULL);
baz(int = -1);
baz(foo*);
baz(ostream&, char*);
};
What name should it use for each one?
---
---------------
* Origin: Tanktalus' Tower BBS (1:250/102)
|