Features of C++
In this article you can read some major features of C++.
Data Declaration in C++
C++ provides the facility of declaration of variables with the statements of the program. In contrast to this we have to declare all the variables at the beginning of a block in ANSI C. But we are fortunate that C++ allows us to declare the variables anywhere in the program but prior to its use. The plus point of this type of declaration is that the program becomes more readable, because the variable is declared and initialized close to where it is actually used.
Following code segment illustrates this:
#include
void main()
{
….
for(int j=1; j<=n; j++) /* OK in C++ but in ANSI C */
{
….
….
}
….
}
This facility is very useful because we can declare a variable when needed and initialize it immediately.
New Looks of Functions
Like C, every C++ program is basically a collection of one more functions in which main() is an essential function. C++ provides several new features to make functions more efficient and safe to use. In C++ we have to declare a function prototype, complete with a list of receiving arguments that the function accepts and its return type. Of course we can use function prototype in C, they are not mandatory. However if we do not want to declare its prototype in C++ then we have to define it before its first call.
Now let us study some new features functions of C++.
Default Arguments in Functions
C++ provides the facility of defining default values for arguments, that are not passed when the function is called, when we provide a prototype for a function. A C++ function prototype can declare that one or more of the function’s argument have default argument values. For example, consider the function Box() which draws a box on the screen. We may provide the default values for the box dimension as follows:
void Box(int x1=5, int y1=5, int x2=20, int y2=75);
Now when a call to the function Box() does not contain the corresponding arguments, the compiler inserts the default values where it expects to see the arguments. Let us understand this concept of default arguments by examining the following code segment:
Box( ); /* same as Box(5, 5, 20, 75) */
….
Box(10, 10); /* same as Box(10, 10, 20 75) */
….
Box(15); /* same as Box(15, 5, 20 75) */
….
Now let us examine this code. When we call the function Box() with no arguments then the function prototype fills x1, y1, x2 and y2 with default values. In second call statement Box(10, 10), the first and second formal arguments are replaced with actual arguments and the third and forth formal arguments will use default values, which is 20 and 75. In third call when we pass only single value then it will replace only first default value, however the remaining three default values will remain. Note that it is impossible to give a non-default value for the x2 argument without specifying the values for x1 and y1. Thus in default arguments case, we will have to remember two main points:
- default values are always been taken from trailing variables.
- default values should be defined where we are defining the function prototype and should not be repeated in function definition.
Overloading Functions
C++ provides the facility of having several functions with the same name. This feature is called overloading function. Function overloading is the process of having unique name for two or more functions as long as their argument lists differ, that is two functions are said to be overloaded if they have identical name and have different argument lists.
C++ provides already some in built overloaded functions. For example, the arithmetic expression
10 + 20
calls the addition operation for integer operands, whereas the expression
10.0 + 20.0
calls a different addition operation that handles floating point operands. Like this we can also define a set of user-defined functions that perform the same general action but that apply to different to argument types. In ANSI C we have three different functions for calculating area of three different shapes, as follows:
float area_circle(float);
float area_triangle(float, float);
int area_rectangle(int, int);
Here each function performs the similar actions, that is each function returns the area of the argument(s) that it receives. In C++ we can use the name area() for all three versions and declare them as follows:
float area(float);
float area(float, float);
int area(int, int);
Here user has to write a separate function definition for each overloaded area() function that has a unique set of parameters. These three functions are called as follows:
….
float radius=20.5;
float base = 10.5;
float height = 19.6;
int length = 15;
int breadth = 20;
….
x = area(radius);
….
y = area(base, height);
….
z = area(length * breadth);
….
Here the C++ compiler selects the corresponding function by comparing the types of arguments in the call with those that are specified in the function’s declaration. It is so because overloaded functions are identified by the values or parameters passed to them. So when a call area(radius) is made then that function will be called which receives one float argument. Similarly when a call area(base, height) is made then that function will be called which receives two float arguments. One main point to note here is that overloaded functions are not identified by what values are returned by them, rather they are identified by the argument lists.
Now the question arises - when to overload a function name and when not. The function overloading is prohibited especially when a set of functions operate on the same of data type but perform different activity; instead such functions should be defined with unique names. The conclusion is that if your program logic needs a certain feature then use it. The programmer should not force to use overloaded function, just for simply it is there, it should be implemented only where it feels natural to use them.
Inline Functions
Generally when a function is called, the control is transferred to that function, along with some values if necessary, and after execution, the control is transferred back to the calling function. Obviously it saves memory space but certainly increases execution time. To reduce this execution time, C++ language provides inline functions.
The syntax of declaring inline functions is
inline function_name(list_of_arguments)
{
// Function body
}
A function is made “inline” by using the keyword inline before the function’s return type of the function definition. Whenever we call inline function, the C++ compiler places the entire code of inline function directly inside the code of the calling function. In other words we can say that inline functions are just like preprocessor macros because the compiler substitutes the entire function body for each inline function call. But these two are differ in a crucial aspect. Let us see where they differ.
Consider the following code segment:
….
#define multiply(a, b) (a*b)
….
x = multiply(6+1, 10);
….
Here the C preprocessor expands this statement as:
x = (6+1* 10);
This evaluates to 16 instead of the result of multiplying (6+1) and 10, which should have been 70. However if we use inline function as:
….
inline multiple(int a, int b)
{
return (a*b);
}
void main()
{
….
….
x = multiply(6+1, 10);
….
}
Now when the inline function multiply() is called, it produces the output correctly, that is 70. Another plus point of inline functions over preprocessor macro is that inline functions can also be overloaded like true functions.
The limitation of inline function is that the entire inline function should always occur before main () or they are called. Don’t get confused between the using of inline and normal functions. If the function code is small, straight-line or when there are relatively few calls to it then use inline function otherwise uses the normal function.
Remember that when we define the function inline, it is up to the C++ compiler whether to insert the code of inline function or not to insert. It is because we are just requesting the C++ compiler. The compiler may ignore this request, because the function declared inline might not be a good candidate for expansion at the point of call. So there is no hard and fast rule that its code must be placed at the place where the call is being made. The compiler may overrule you without saying so.
Friend Functions
One of the important features of object-oriented programming is data hiding of data members. The rules of data hiding is that only member functions of a class can access the private data of a class. But sometime we need to operate on private data members of two classes outside those classes. This facility is provided by using a friend function. A friend function is used to operate on objects of two different classes. Logically, such a function should be a member of both classes. But it is impossible. The only way to achieve this goal is by using a friend function that acts as a bridge between two different classes. A friend function belongs to neither, and able to access both.
Following code segment illustrates this concept.
….
class Sample;
class Example
{
private :
int i;
public :
Example (int ii)
{
i=ii;
}
friend int add(const Example &ff, const Sample &ss);
};
class Sample
{
private :
int j;
public :
Sample (int jj)
{
j=jj;
}
friend int add(const Example &ff, const Sample &ss);
};
int add(const Example &ff, const Sample &ss)
{
int temp;
temp = ff.i+ss.j;
return temp;
}
void main()
{
Example f(100);
Sample s(200);
int number;
number = add (f, s);
cout << number;
}
When we run this program, we get the following output….
300
In this code segment we have used to two classes Example and Sample. The constructor in these classes initialize their private data member i and j to 100 and 200 respectively. In both classes we have declared a function add() to access their private data member as:
friend int add(const Example &ff, const Sample &ss);
This declaration can be placed anywhere in the class, either in private section or in the public section. Note that the friend declaration is necessary in both classes. Another notable point is the declaration class Sample; at the beginning of the program. This forward declaration is necessary because we can not refer a class until it has been declared. The class Sample is being referred to in the declaration of the function add() in class Example. So class Sample must be declared before Example.
This declaration tells the compiler that the class Sample is defined later. However, If we do not do this then the compiler can not understand the Sample type when it encounters the Example’s friend declaration and therefore the compiler will report an error message. If you place the entire class Sample definition before class Example then the compiler would not know what the Example type is when it encounters the friend declaration in the Sample class type. That’s why it is necessary to use the forward declaration.
Look at the definition for add(). This does not use the keyword friend and the scope resolution operator (::). The keyword friend is used only for the prototype appearing in a class using the function and the scope resolution operator is not used because this friend function does not belong to any class. It means that the friend function has file scope, rather than class scope. Thus there will only one friend function with a specific name and signature (list of arguments received) per file.
Struct in C++
Another important features of C++ is that we can start using the name of a struct as soon as its definition is started. In C, let we have following self-referential structure as:
typedef struct Employee
{
char name[20];
int age;
float salary;
struct Employee *link; /* pointer to another Employee node */
} Employee;
Employee *e; /* define an Employee node */
However in C++ we can have the same code in much simpler way, as follows:
struct Employee
{
char name[20];
int age;
float salary;
Employee *link; /* pointer to another Employee node */
} ;
Employee *e; /* define an Employee node */
This code segment shows that the name of a struct can be used inside the definition of the struct itself. Note that C++ structures offer more than their C counterparts: they can hold functions declaration and definitions as well as data members. Following code segment illustrates this:
struct Employee
{
char name[20];
int age;
float salary;
void getdata()
{
cin >> name >> age >> salary;
}
void display()
{
cout << name << age <
}
};
We access the member function of a struct in the same way we access its data members, that is using a dot (.) operator.
Introduction to Reference
A reference is referred to as an alias or synonym, that is an alternate name for another variable. Using reference we can pass large amount of data without the overhead of copying them. References are much like pointers. You can do anything with a reference that you can do with a pointer. Of course pointer also is an important feature of C and C++, but sometimes it may trouble you and even a good programmer for some complex operations. However it has certainly some plus points over pointers.
A reference is declared using the type specifier with the address-of (&) operator. A reference must be initialized when it is declared. Following code segment illustrates this :
….
int a=10;
int &b = a; // declaration and initialization of a reference variable
….
Here we have declared an integer variable, a, that has another name, b. Note that a reference can not be made to refer to another variable once it is initialized o some variable. If you make any change to a reference then that change is actually applied to the variable to which the reference refers. For example,
b+= 5;
adds 5 to a, the variable referred to by b. Another main point to note that each definition of a reference must be preceded by the address of operator. For example,
int &x = a, y = b;
defines one reference and one variable.
Another main point to remember is that a reference is neither a copy nor a pointer to the object to which it refers. Instead it is just like another name. Look at the following code segment:
….
int a = 20 ;
int & b = a;
cout << “\n a = ” << a << “ Address of a = ” << &a ;
cout << “\n b = ” << b << “ Address of b = ” << &b ;
….
The output of this code segment is
a = 20 Address of a = Ox8facfff420
b = 20 Address of b = Ox8facfff420
Thus we can say that the two addresses are same.
Standard I/O
We know that ANSI C provides all the standard library I/O functions in the stdio library. C++ also provides the stdio library as well as a group of classes and fuctions for I/O defined in the iostream library. To access these, we must include the directive #include in our program. There are many advantages in using iostream rather than stdio, such as the syntax is simpler, more elegant, and more intuitive in C++ than in ANSI C, formatting output is simplifier by extensive use of overloading operators, etc.
C++ provides four predefined stream objects defined as follows:
- cin – standard input object, usually associated with the keyboard, and corresponding to stdin in C
- cout – standard output object, usually associated with the display, and corresponding to stdout in C
- cerr – standard error object, usually associated with the display, and corresponding to stderr in C
- clog – a buffered version of cerr (no C equivalent)
We can easily redirect these standard streams from and to other devices and files. There are several classes in iostream library. The istream class includes overloaded definition for the >> operator for the standard data type
(int, long, double, float, char and char *(string)).
For example, in the following statement
cin >> n;
the C++ compiler calls the appropriate >> operator function for the istream cin defined in iostream.h and uses it to direct this input stream into the memory location represented by the variable ‘n’. Similarly the ostream class includes overloaded definition for the << operator for the standard data type (int, long, double, float, char and char *(string)). Thus
cout << n;
sends the value of ‘n’ to ostream cout for output. Since the return type of these both operator functions are a reference to the appropriate stream class type in addition to moving the data, we can use these operators in cascading manner for input or output sequence of characters:
cin >> a >> b >> c;
cout << a << b << c;
We can also cascade two or more different data types in a single statement using cout as:
…
int age=20;
float salary=20000.50;
char name[20];
cout << "Name : " << name << "Age : " << age << "Salary : " << salary;
….