The C Programming Language is deliberately small and simple, making it relatively easy for programmers to port the compiler to new systems. Programs often use the arithmetic operations (+, -, *, /, and &), but they too are small and simple. Alternatively, the sqrt
, pow
, and similar functions are more complex but used less often, making them better suited for inclusion as library functions. Library functions are often tied tightly to specific data types, frequently requiring programs to cast their data to or from the function's types.
double sqrt(double x); |
float sqrtf(float x); long double sqrtl(long double x); |
(a) | (b) |
double
data, requiring type casts to deal with other data types.double sqrt(double x); float sqrt(float x); long double sqrt(long double x); |
double sqrt(double x);
float sqrt(float x);
long double sqrt(long double x);
double sqrt(T x); |
(a) | (b) |
C++ is an extensible language, meaning that programmers can add new data types to their C++ programs without modifying the compiler or the language's syntax. C++ allows programmers to create new types with enumerations, structures, and classes. Although extensibility is a powerful feature, it makes creating library functions challenging. Data structures effectively illustrate the challenge.
The operations necessary to manage a data structure (e.g., insert, search, remove, etc.) are largely independent of the saved and organized data. Data independence makes data structures good candidates for inclusion in programming libraries, but only if programmers can generalize the data they save. C programs use void pointers as a general data type, which works but is clumsy, potentially confusing, and error-prone. To "cleanly" generalize the data, we need a programming mechanism that embraces C++'s extensibility and integrates more seamlessly into its existing features. Ideally, we want a mechanism that allows us to separate the organizational and data manipulation operations. Containers (called collections in Java) are data structures that store and organize data, demonstrating the separation.
Linked lists and binary trees are familiar container examples. Containers like binary trees organize the contained data by value. For example, if each data item is a student record, the container can organize it by name or ID. Formally, such data must be orderable, and in object-oriented programs, the data class itself typically provides the ordering function as a member. Templates allow programmers to create container classes with all the necessary organizational operations without regard to the stored data type. Programmers use a template variable name, often T, as a placeholder whenever the code refers to the saved or contained data type. During the compilation process, the compiler replaces the placeholder name with a program-supplied type name. We explore template classes in the third chapter section.
Although the implementing mechanisms are different, C++ templates look and behave like Java's generic classes, solving the same problems. However, C++ is a hybrid language that supports both the procedural and the object-oriented programming paradigms - where Java only supports the object-oriented paradigm. As a consequence, C++ programmers can also use templates with non-member functions.