Some extensions of C in C++
1: The scope operator ::
This operator can be used in situations where a global variable exists
with the same name as a local variable:
#include <stdio.h>
int
counter = 50; // global variable
int main()
{
for (int counter = 1; // this refers to the
counter < 10; // local variable
counter++)
{
printf("%d\n",
::counter // global variable
/ // divided by
counter); // local variable
}
return (0);
}
2: cout, cin and cerr
In analogy to C, C++ defines standard input- and output streams
which are opened when a program is executed. The streams are:
-
cout, analogous to stdout,
-
cin, analogous to stdin,
-
cerr, analogous to stderr.
Syntactically these streams are not used with functions: instead, data
are read from the streams or written to them using the operators <<,
called the insertion operator and >>, called the extraction
operator. This is illustrated in the example below:
#include <iostream.h>
void main()
{
int
ival;
char
sval[30];
cout << "Enter a number:"
<< endl;
cin >> ival;
cout << "And now a
string:" << endl;
cin >> sval;
cout << "The number
is: " << ival << endl
<< "And the string is: " << sval << endl;
}
This program reads a number and a string from the cin stream
(usually the keyboard) and prints these data to cout. Concerning
the streams and their usage we remark the following:
-
The streams are declared in the header file iostream.
-
The streams cout, cin and cerr are in fact `objects'
of a given class (more on classes later), processing the input and output
of a program.
-
The stream cin reads data and copies the information to variables
(e.g., ival in the above example) using the extraction operator
>>.
-
Special symbolic constants are used for special situations. The termination
of a line written by cout is realized by inserting the endl
symbol, rather than using the string "\n".
Whether a program uses the old-style functions like printf() and
scanf()
or whether it employs the new-style streams is a matter of taste. Both
styles can even be mixed. A number of advantages and disadvantages is given
below:
-
Compared to the standard C functions printf() and scanf(),
the usage of the insertion and extraction operators is more type-safe.
The format strings which are used with printf() and scanf()
can define wrong format specifiers for their arguments, for which the compiler
sometimes can't warn. In contrast, argument checking with cin,
cout
and cerr is performed by the compiler. Consequently it isn't possible
to err by providing an int argument in places where, according
to the format string, a string argument should appear.
-
The functions printf() and scanf(), and other functions
which use format strings, in fact implement a mini-language which is interpreted
at run-time. In contrast, the C++ compiler knows exactly which
in- or output action to perform given which argument.
-
The usage of the left-shift and right-shift operators in the context of
the streams does illustrate the possibilities of C++. Again, it
requires a little getting used to, coming from C, but after that
these overloaded operators feel rather comfortably.
The iostream library has a lot more to offer than just cin,
cout and
cerr.
3: References
Besides the normal declaration of variables, C++ allows `references'
to be declared as synonyms for variables. A reference to a variable is
like an alias; the variable name and the reference name can both be used
in statements which affect the variable:
int
int_value;
int
&ref = int_value;
In the above example a variable int_value is defined. Subsequently
a reference ref is defined, which due to its initialization addresses
the same memory location which int_value occupies. In the definition
of
ref, the reference operator & indicates that
ref
is not itself an integer but a reference to one. The two statements
int_value++;
// alternative 1
ref++;
// alternative 2
have the same effect, as expected. At some memory location an int
value is increased by one --- whether that location is called int_value
or
ref does not matter.
References serve an important function in C++ as a means to
pass arguments which can be modified. E.g., in standard C, a function
which increases the value of its argument by five but which returns nothing
(void), needs a pointer argument:
void increase(int *valp) // expects a pointer
{ // to an int
*valp += 5;
}
int main()
{
int
x;
increase(&x) // the address of x is
return (0); // passed as argument
}
This construction can also be used in C++ but the same effect
can be achieved using a reference:
void increase(int &valr)
// expects a reference
{
// to an int
valr += 5;
}
int main()
{
int
x;
increase(x);
// a reference to x is
return (0);
// passed as argument
}
Our suggestions for the usage of references as arguments to functions
are therefore the following:
-
In those situations where a called function does not alter its arguments,
a copy of the variable can be passed.
-
When a function changes the value of its argument, the address or a reference
can be passed, whichever you prefer.
-
References have an important role in those cases where the argument will
not be changed by the function, but where it is desirable to pass a reference
to the variable instead of a copy of the whole variable. Such a situation
occurs when a large variable, e.g., a struct, is passed as argument,
or is returned from the function. In these cases the copying operations
tend to become significant factors when the entire structure must be copied,
and it is preferred to use references. If the argument isn't changed by
the function, or if the caller shouldn't change the returned information,
the use of the const keyword is appropriate and should be used.
A number of differences between pointers and references is pointed out
in the list below:
-
A reference cannot exist by itself, i.e., without something to refer to.
-
References can, however, be declared as external. These references
were initialized elsewhere.
-
Reference may exist as parameters of functions: they are initialized when
the function is called.
-
References may be used in the return types of functions. In those cases
the function determines to what the return value will refer.
-
Reference may be used as data members of classes.
-
In contrast, pointers are variables by themselves. They point at something
concrete or just ``at nothing''.
-
References are aliases for other variables and cannot be re-aliased to
another variable. Once a reference is defined, it refers to its particular
variable.
-
In contrast, pointers can be reassigned to point to different variables.
-
When an address-of operator & is used with a reference, the
expression yields the address of the variable to which the reference applies.
In contrast, ordinary pointers are variables themselves, so the address
of a pointer variable has nothing to do with the address of the variable
pointed to.
5: The `bool' data type
In C the following basic data types are available: void, char,
int, float and double. C++ extends these five basic
types with several extra types.
The type bool represents boolean (logical) values, for which
the (now reserved) values true and false may be used.
Apart from these reserved values, integral values may also be assigned
to variables of type
bool, which are implicitly converted to true
and false according to the following conversion rules (assume
intValue
is an int-variable, and boolValue is a bool-variable):
// from int to bool:
boolValue = intValue ? true : false;
// from bool to int:
intValue = boolValue ? 1 : 0;
Furthermore, when bool values are inserted into, e.g., cout,
then
1 is written for true values, and 0 is
written for false values. Consider the following example:
cout << "A true value: " << true << endl
<< "A false value: " << false << endl;
Using the bool-type is generally more intuitively clear than using
int.
As a rule of thumb we suggest the following: If a function should inform
its caller about the success or failure of its task, let the function return
a
bool value. If the function should return success or various
types of errors, let the function return enum values, documenting
the situation when the function returns. Only when the function returns
a meaningful integral value (like the sum of two int values),
let the function return an int value.
6: The `wchar_t' data type
The wchar_t type is an extension of the char basic type,
to accomodate
wide character values, such as the Unicode
character set.
Sizeof(wchar_t) is 2, allowing for 65,536 different
character values.
Note that a programming language like Java has a data type char
that is comparable to C++'s wchar_t type, while Java's
byte
data type is comparable to C++'s char type. Very convenient....
7: The `string' data type
The C programming language offers rudimentary string support: the
ascii-z terminated series of characters is the foundation on which
a large amount of code has been built. Standard C++ now offers a
string type of its own. In order to use
string-type objects,
the header file string must be included in sources.
Actually, string objects are class type variables. The
operations that can be performed on strings take the form
stringVariable.operation(argumentList)
For example, if string1 and string2 are variables
of type string, then
string1.compare(string2)
can be used to compare both strings. The string class offers
a large number of these memberfunctions, as well as extensions of some
well-known operators, like the assignment (=) and the comparison
operator (==).
8: Data hiding: public, private and class
C++ contains special syntactical possibilities to implement data
hiding. Data hiding is the ability of one program part to hide its data
from other parts; thus avoiding improper addressing or name collisions
of data.
C++ has two special keywords which are concerned with data hiding:
private
and public. These keywords can be inserted in the definition of
a struct. The keyword public defines all subsequent fields
of a structure as accessible by all code; the keyword private
defines all subsequent fields as only accessible by the code which is part
of the
struct (i.e., only accessible for the member functions)
(Besides
public and private, C++ defines the keyword
protected.
This keyword is not often used and it is left for the reader to explore.).
In a struct all fields are public, unless explicitly
stated otherwise.