C++ Better C Enhancements

Lecture 2: C++ "Better C" Enhancements
2.1 Scopes
scope
|
the parts of a program where a particular declaration or
definition applies
|
- local (blocks/compound statements) - hidden global name can be accessed using the global operator ( :: )
- function (only applies to goto labels)
- file (globals and extern declarations)
- class (nested typedefs and classes - this scope is new with C++)
l-value
|
an expression which refers to an object
Such an expression can appear on the left side of an assignment operator
unless it's a constant. |
2.3 Types
Type-conversion syntax: long(p) or (long)p. Used sparingly in C++ - implicit conversions are emphasized.
An enumeration is considered to be a distinct integer type. Its values may be assigned to correspond to specific integers (as in C), and it undergoes integer promotion so it can be used wherever an integer is required, but only the enumerator constants can be assigned to it (not even their integer equivalents).
In C++, any pointer can be assigned to a void * without a cast, but not vice versa as in C. This is a type safety enhancement.
In C++ structs are a completely public form of class and as such aren't used very often. In C++, an isolated reference to the tag can be used to refer to the structure. This usage is also allowed for other objects like unions and enums which have tags. No struct prefix necessary. This obviates a major use to which typedefs are put in C.
A union is a struct in which all the members share the same area of memory. Used for space saving. C++ allows the use of anonymous unions - a syntactic convenience.
Prototypes are mandatory in C++, not optional as in C.
A new bool type has been introduced in C++.
2.4 Constant Variables
Obviate a major use of #define in C++. Constant variable declarations can go in header files.
2.5 const
In defining arguments, absence of const is as significant as its presence. It should be present if at all possible, since its presence makes a function more usable.
"Disallowing conversions for non-const reference arguments avoids the possibility of silly mistakes arising from the introduction of those temporaries." (Stroustrup, p. 126) When an reference argument to a function is not const, that indicates part of the expected behavior of the function is to possibly change the state of the object. If the reference is of the wrong type, and the compiler were to do a conversion and pass a reference to the converted object to the function, the function would change the state of the converted object and leave the state of the original object unchanged which would possibly frustrate the intended effects of the function.
2.6 References
This is not in C though familiar from FORTRAN and PASCAL. It is an alternative name for an object. It must be initialized. As well as in declarations of ordinary variables, it sees use as a declaration for function arguments and return values. In this context, it is a good idea to review parameter passing behavior of C functions.
swap() example shows relation between pointers and references. There are important differences: pointer can be changed to point to something different or nothing at all.
Do not return addresses of or references to local variables which will disappear when function exits.
2.7 Default Values for Function Arguments
Note only trailing args can be defaulted. Function overloading can be used to get the same effect with or without this restriction. Variable arg lists still available in C++. Many times their convenience for passing constructed lists outweighs their type safety problems (eg XtSetValues() vs. XtVaSetValues()).
2.8 Inline Functions
These work just like macros except they don't have side effects. They have the same trade-offs as macros. They should be used where the time required for the function call is significant in comparison to the operation being done or when a function call is pretty much an alternative interface to another function.
It's worth noting that the code generated with inline functions may be smaller than when it is not inlined since the optimizer cannot go behind a function call but it can integrate inline code with the surrounding code.
With this facility and that provided by const, there's practically no reason to ever use the preprocessor #define directive.
2.9 Dynamic Memory Allocation
Memory allocation is now built into the language. malloc() and free() also become obsolete in C++ being replaced by new and delete operators which are integrated into the language. new is more type safe than malloc() was, and syntax is less obscure and closer to that used to create automatics.
As with free(), a 0 pointer can be passed to delete with no ill effects. delete must be followed by brackets when applied to an array. Doesn't seem to be any substitute for realloc().
Default behavior of new is like malloc() in that it returns 0 if there's no memory (assuming new_handler() returns which, by default, it doesn't). However, tedious procedure of checking every new allocation for 0 can be avoided by using PVF set_new_handler(PVF) (typedef void (*PVF)();) function to define function to be called in event of memory exception. new calls new_handler() in the event of a memory allocation failure. By default, new_handler() calls abort().
Example:
char *strdup(const char *in) {
char *out = new char[strlen(in) + 1];
return strcpy(out, in);
}2.10 Standard I/O: Basics
Quite a bit different from C. We will study facilities in their totality later. The C++ facilities are more type safe and extensible than what C provides ( printf() etc.).
Instead of a function, objects ( cerr, cout, cin) and overloaded operators (<< and >>) are used. << is old left shift operator which is now called "put to" or "insertion" operator. >> is old right shift operator and now called "get from" or "extraction" operator.
Examples:
cout << "x = " << x << '\n';
cerr << "Error: " << msg << '\n'; // char *msg
cin >> x >> y;There is a default method for printing each type. Impossible to print out type wrong way as with printf(). Also scanf() problem of compiler not being able to flag when a value is specified instead of a pointer is obviated. Left-to-right associativity ensures the expected result obtains. In this context, the value of << or >> is always a reference to its left-hand side.
In addition, a stream can be used as a control expression to see if an invalid operation (like reading past the end of a file) has been attempted.
Examples:
if (cin) ... // everything ok
else ... // handle error
if (!cin) ... // handle error
else ... // everything okBy default, >> for the char type skips white space. In situations where this is not desirable, istream::get() or istream::get(char &) can be used. The first version works exactly like the stdio.h getchar() function.
Example: int c; while((c = cin.get()) != EOF) ...
The second version returns a reference to an istream and so the call can be imbedded in a control statement.
Example: char c; while(cin.get(c)) ...
Another handy member function for any stream is eof(). This returns non-zero if a read has been attempted past the end of the stream.
0 comments: