21.3 New Type-Casting Operators
21.11 The Standard Namespace std
21.12 ANSI and Turbo-C++ Keywords
This chapter deals with various concepts that have not been discussed so far, including new improvements suggested by the ANSI committee in C++ language. In addition, this chapter also contains information regarding additional keywords provided by Turbo C++. A list of commonly useful header files is also given.
The aim behind the improvements made by ANSI is to enable the programmer to develop real-world application programs in a simple and easy manner. The new characteristics added enabled a programmer improved achievements in complicated conditions. It is also possible to build programs without using the new characteristics. However, with additional features, the source code will be reduced for complex problems, and programs can be made shorter and more efficient.
The ANSI/ISO committee introduced new data types to enable a better scope of standard data types in C++. These new data types are bool and wchart_t.
The bool is a keyword. The bool data type is used to hold Boolean values, that is, true and false. The true and false are also keywords. The C++ treats true and false as values. The default numeric value of false is zero, and that of true is one. All conditional expressions return values of this type. For example, the expression 5>4 is true, and it returns one. The variables of these data types are declared in the following manner:
bool t1; |
// t1 is a variable of bool data type |
t1 = true |
// t1 contains true (1) as value |
bool f1 = false |
// declaration and initialization are |
//done with same type |
These bool data-type variables can be used in mathematical expressions as per the following statement:
int m = true+2*5+t1;
When bool data types are used in expressions such as the one above, they are automatically evaluated to integers. It is also possible to change by nature the data-type pointers, floating and integer values to the bool data type.
bool a= 1; |
// Variable a contains true value |
bool b=0 |
// Variable b contains false value |
bool c=1.2 |
// Variable c contains true value |
21.1 Write a program to declare bool variables and display the values.
#include<iostream>
using namespace std;
int main()
{
bool t=true;
bool f=false;
cout<<“ t=”<<t;
cout<<“ f=”<<f;
bool g=1;
cout<<“ true”;
else
cout<<“ false”;
return 0;
}
OUTPUT
t = 1
f = 0
true
Explanation: In the above program, t and f are variables of the bool data type. The variable t contains true, and f contains false. Values of these variables are displayed using the cout statement. The variable g is another variable of the bool data type and contains value 1, that is, true. The if statement checks the value of the variable g and displays the appropriate message.
21.2 Write a program to declare variables of bool data type and use in mathematical expressions.
#include<iostream>
using namespace std;
int main()
{ bool t=true;
bool h,f=false;
cout<<“ t=”<<t;
cout<<“ f=”<<f;
int x= 4*t+5*f;
h=x;
cout<<“ x=”<<x;
cout<<“ h=”<<h;
return 0;
}
OUTPUT
t = 1
f = 0
x= 4
h= 1
Explanation: In the above program, t and h are variables of the bool data type and contain the values true and false. The variable x is an integer variable. The variables t and f are used in mathematical expressions, and the result obtained is assigned to the variable x. The value of the integer variable x is assigned to the Boolean variable h. The output of the program is as given above.
In case the variable of the bool type is assigned a value more than 1, for example bool x = 2; here, the value of x will be considered true, that is, 1. The variable of the bool type also supports the increment ++ (postfix or pre-fix) operation. However, it cannot support the decrement (--) operation. When a bool-type variable with the value 0 (false) is incremented, its value becomes one. However, when a variable contains Boolean value one and if any attempt is made to increase it, its value remains the same.
21.3 Write a program to perform increment operation with variable of bool type.
#include<iostream>
using namespace std;
int main()
{
bool x=0;
++x;
cout<<x;
return 0;
}
OUTPUT
1
Explanation: In the above program, x is a variable of the type bool. It is initialized with the value 0 (false). When the variable x is incremented, it contains one (true). The increment operator can be applied either prefix or postfix.
The wchar_t is a character data type that holds 16-bit-long/-wide characters. The 16-bit characters are manipulated to symbolize the character sets of languages that contain more than 255 characters. ANSI C++ also defined a character literal called as wide_character literal. It occupies two bytes in memory. The wide_character literal starts with the letter L, as follows:
L ‘ab’
It is known as wide_character literal.
The declaration of wchar_t in the header file stdlib.h is as follows:
typedef char whcr_t;
The following program demonstrates the use of the wchar_t data type.
21.4 Write a program to use wchar_t data type.
#include<iostream.h>
#include<stdlib.h>
#include<constream.h>
void main()
{
clrscr();
wchar_t c=’A’;
cout<<c;
}
OUTPUT
A
Explanation: In the above program, variable c is of type wchar_t and it is initialized with “A.” The cout statement displays the same on the screen.
We have studied that a type-casting operation is used to change a value from one type into another. This can be applied at a place where the automatic conversion of data types is not done.
double b = (double)j |
// c type-casting style |
double a = double (d) |
// c++ type-casting style |
The above statements are correct, and nothing wrong happens when they are applied in practical applications. New type-casting operators introduced by the ANSI/ISO committee are as follows:
(1) The static_cast operator
The static_cast operator is used for the conversion of standard data types. Using this operator, base class pointers can be converted into derived class pointers. Their syntax is as follows:
static_cast <data-type> object
The data_type indicates the target data type of the cast. The specified object is converted into a new data type. The new syntax of type casting is easy. Hence, the above keyword is frequently used by the programmer instead of the old format.
21.5 Write a program perform type casting using static_cast operator.
#include<iostream.h>
int main()
{
int k=65;
cout<<“ size of k=”<<sizeof(k);
cout<<“ value of k=”<<k;
double d=static_cast<double>(k);
cout<<“ size of d=”<<sizeof(d);
cout<<“ value of d=”<<d;
char c=static_cast<char>(k);
cout<<“ c=”<<c;
return 0;
}
OUTPUT
size of k=4
value of k=65
size of d=8
value of d=65
c = A
Explanation: In the above program, the integer k is initialized with 65. The variable d is of a double data type. The value of k is assigned to d using the static_cast operator. The value of k is assigned to char data-type variable c. The output displays the contents of the variable with the numbers of bytes occupied by them.
(2) The const_cast operator
The const_cast operator explicitly modifies the const or volatile of a variable. It is used in the following format:
const_cast <data-type> (object)
In this type of casting, our goal is to change the const or volatile nature of the variable. Hence, target and source data types are identical. This type of casting is frequently applied for removing the const attribute of a variable.
21.6 Write a program to convert constant to non-constant.
#include<iostream.h>
void main()
{
const int x=0;
p=const_cast<int*>(&x);
}
class data
{private:
int d;
public:
void joy() const
{
(const_cast<data*>(this))->d=100;
}
};
Explanation: In the above program, the address of the constant variable is assigned to the pointer of the non-constant variable, and this is done using the operator const_cast.
(3) The reinterpret_cast operator
The reinterpret_cast operator is useful when the programmer wants to transform one type into a dissimilar type. In practical applications, it is used to modify a pointer kind of an object to an integer kind or vice versa. It is used in the following format:
reinterpret_cast <data-type> (object )
21.7 Write a program to convert pointers to integers using reinterpret_cast operator.
#include<iostream.h>
void main()
{
int b=487;
int *rp=reinterpret_cast<int*>(b);
cout<<endl<<“rp=”<<rp;
rp++;
cout<<endl<<“rp=”<<rp;
b=reinterpret_cast<int>(rp);
cout<<endl<<“b=”<<b;
b++;
cout<<endl<<“b=”<<b;
}
OUTPUT
rp=0x000001E7
rp=0x000001EB
b=491
b=492
Explanation: In the above program, b is an integer type of variable and initialized with 487. The variable rp is a pointer and initialized with the address of the variable. The rp is increased and the value is increased by four. The output shows the values of the variable.
21.8 Write a program to convert void pointer to char pointer using reinterpret_cast operator.
#include<iostream.h>
#include<string.h>
void *getadd()
{
static char text[50];
return text;
}
void main()
{
char *p=reinterpret_cast<char*>(getadd());
//char *p=getadd();
strcpy (p,” Well Come”);
cout<<p;
}
OUTPUT
Well Come
Explanation: In the above program, the function getadd() returns the base address of the array text [50] as a void address. The return type is void *. In the function main(), the obtained address is converted into character type using the operator reinterpret_cast and assigned to the character pointer p. The strcpy() function copies a string to the pointer p. Finally, the cout statement displays the text stored in the pointer p.
(4) The dynamic_cast operator
The dynamic_cast operator is used to change the type of an object during program execution. It is frequently used to type cast on polymorphic objects, that is, when the base class has a virtual function. This operator casts the base class pointer onto the derived class pointer. The operation with dynamic_cast is also known as type-secure downcast. It is used in the following format:
dynamic_cast <data-type> (object)
The object should be a base class object. Its type is tested and altered. This always does valid conversion. It verifies that the casting is allowable at execution time. It returns null, in case type casting is defective.
(5) RTTI using typeid operator
The runtime type information (RTTI) is a new improvement made by the ANSI/ISO committee. The typeid() operator is used to obtain the exact type of object or variable during program execution. This operator returns a reference to an object maintained by the system. This object identifies the type of argument. Its syntax is as follows:
char *object class = typeid (object). name();
21.9 Write a program using typeid() to identify the type of object.
#include<iostream.h>
#include<typeinfo.h>
class one
{
public:
virtual void say()
{
}
};
class two: public one
{};
class three: public one
{};
void main()
{
one *o;
cout<<endl<<typeid(o).name();
two *t;
cout<<endl<<typeid(t).name();
}
OUTPUT
class one *
class two *
Explanation: In the above program, class one has one virtual function, say(). Class two is derived from class one. In the function main(), *o and *t are pointer objects of class one and two, respectively. The typeid() operator identifies the type of objects and displays the class name from which they are created.
21.10 Write a program to identify the type of variable using typeid().
#include<iostream.h>
#include<typeinfo.h>
void main()
{
int i;
float f;
cout<<endl<<typeid(f).name();
}
OUTPUT
int
float
Explanation: In the above program, two variables of int (i) and float (f) are declared. Using the typeid() function, their types are displayed. The output is int, float, that is, the type of variables (i) and (f).
The keyword explicit is advantageous in order to declare the constructors of a class as being explicit. When a constructor is invoked with a single argument, implicit conversion is carried out. In this operation, automatic conversion is performed. The type of argument taken is modified to an object type. To avoid such automatic-type conversion, the keyword explicit is used followed by the constructor name. The above program explains the use of the keyword explicit.
21.11 Write a program to declare explicit constructor and avoid automatic conversion.
#include<iostream.h>
class XYZ
{
int k;
public:
explicit XYZ (int j)
{k=j;}
void show()
{
cout<<“ k=”<<k;
}
};
int main()
{
XYZ XY(545);
// XYZ XY=450; invalid assignment
XY.show();
return 0;
}
k=545
Explanation: In the above program, the class XYZ is declared with a one-integer argument. The class also has a one-argument constructor followed by the keyword explicit and one member function show(). In the function main(), the statement XYZ XY (545) creates an object XY and initializes the member variable k with the number 545. The statement XYZ XY = 450 is invalid, because the constructor is explicit and does not permit automatic conversion. This statement is valid only when the class constructor is not declared as being explicit.
We learned that a member function or object can be declared as constant using the keyword const. The constant data elements are not modified, and the constant member function can alter the value of any variable. The mutable is used when we need to declare a constant object but partly, that is, a specific data variable can be modified. Thus, the data variable that is to be modified is declared as mutable. The declaration is as follows:
mutable int k;
Here, the variable k can be modified though its class or object is declared as constant.
21.12 Write a program to use mutable keyword and modify the value of variable.
#include<iostream>
using namespace std;
class XYZ
{
private:
mutable int k;
public:
explicit XYZ (int d) {k=d;}
void value() const {k+=10;}
void show() const {cout<<“ k=”<<k;}
};
int main()
{
const XYZ x(75);
x.show();
x.value();
x.show();
return 0;
}
k= 75
k= 85
Explanation: In the above program, the class XYZ is a one-integer mutable member. The class also has value() and show() constant member functions. In the function main(), the x is a constant object of class XYZ. When x is declared, the mutable member k is initialized with 75. When the value() function is invoked, it is incremented with 10. The show() function displays the values of the variables.
C++ allows defining variables with a different scope such as local, global, blocks, classes, functions, etc. This can be done using the keyword namespace introduced by ANSI C++. The C++ standard library is the better example of namespace. All classes, templates, and functions are defined inside the namespace std. In the previous programs, we used the statement using namespace std. This tells the compiler that the members of this namespace are to be used in the current program.
The namespace can be defined in the programs. The declaration of a namespace is similar to a class declaration except that the namespace is not terminated by a semi-colon. It is declared in the following format:
namespace namespace_identifier
{
// Definitions of variables function and classes, etc.
}
Example
namespace num
{
int n;
void show (int k) {cout<<k;}
}
In the above example, the variable n and the function show() are within the namespace scope num. We cannot access the variable m directly. To access the variable and initialize it with a value, the statement would be as follows:
num :: n=50;
Here, n is initialized to 50. The scope access operator is used to access the variable. This method of accessing elements becomes embarrassing. We can also access elements directly using the following declarations:
using namespace namespace_identifier // directive statement
using namespace_identifier :: member // declaration method
The first statement allows the access of elements without using a scope access operator. The second statement allows access to only given elements.
using name space num |
|
n=10; |
// valid statement |
show(15); |
// valid statement |
using name space :: n; |
|
m=20; |
// valid statement |
show(14) |
// invalid statement |
It is also possible to declare a nested namespace. When one namespace is nested in another namespace, it is known as a nested namespace.
namespace NUM
{
statement1;
namespace NUM1
{
int k = 10;
}
statement2;
}
The variable k can be accessed using the following statements:
cout<<NUM::NUM1::K
OR
using namespace NUM;
cout<<NUM1::k;
A namespace without a name is known as an anonymous namespace. The members of anonymous namespaces can be accessed globally in all scopes. The frequent use of such a namespace is to protect global members from same name classes among files. Each file possesses a separate anonymous namespace. The following programs explain the use of namespaces:
21.13 Write a program to create namespace, declare, and access elements.
#include<iostream>
using namespace std;
namespace num
{
int n;
void show() {cout<<“ n=”<<n;}
}
int main()
{
num::n=100;
num::show();
return 0;
}
OUTPUT
n=100
Explanation: In the above program, the namespace num contains one integer member n and one member function show(). In the function main(), the variable n is initialized to 100. The members are accessed using a scope access operator and the namespace name. The function show() displays the value of the variable.
Using directive
The keyword using can be used for a declaration as well as a directive. The using directive provides access to all variables declared within the namespace. When using the directive method, we can directly access the variable without specifying the namespace name. The following example illustrates this:
21.14 Write a program to create namespace, declare, and access elements. Use using directive method.
#include<iostream>
using namespace std;
namespace num{
int n;
}
int main()
{
using namespace num;
n=100;
show();
return 0;
}
OUTPUT
n=100
Explanation: In the above program, the namespace name is created with a one-integer variable n function show(). The statement using namespace num allows direct access to members of the namespace. Hence, in the function main(), n = 100 initializes n with 100 and show() displays the value of n on the screen.
Using a declaration:
In this method, the keyword using is optional. It is also possible to access a few members of the namespace directly outside the namespace. The following program explains the above points:
21.15 Write a program to use declaration method of namespace and access variables.
#include<iostream>
using namespace std;
namespace num
{
int n;
void show()
{cout<<“ n=”<<n;}
}
int main()
{
//using namespace num;
num::n=100;
num::show();
return 0;
}
OUTPUT
n=100;
Explanation: The above program is similar to the previous one. The only difference is that here the namespace num is not included. In order to access the elements of namespace num, we need to precede the variable name with a scope access operator and a namespace name. The statement num::n = 100; accesses the variable n and initializes it with 100. In the statement num::show(); the function show() is invoked using the same syntax.
21.16 Write a program to use declaration method of namespace and access variables and functions.
#include<iostream>
using namespace std;
namespace num
{
int n;
void show()
{cout<<“ n=”<<n;}
}
int main()
{
//using namespace num;
using num::n;
n=100;
num::show();
return 0;
}
Explanation: In the above program, the statement using num::n; brings the variable n in the current scope; that is, after this statement, it can be accessed directly by its name, for example, n = 100. Here, 100 is initialized to n. However, other variables (other than n) can be accessed by preceding a namespace name before their name such as num::show().
using namespace num;
The above statement allows to access all members of the namespace num directly, and this style of accessing the elements of g namespace is called a using directive.
using num::n;
The above statement allows to access only member variable n of the namespace. The other member cannot be accessed directly. The member other than n can be accessed by specifying the namespace name before the member name as discussed earlier. This style of accessing elements is knows as a using declaration.
21.17 Write a program to declare nested namespace and anonymous namespace.
#include<iostream>
using namespace std;
{
int j=200;
namespace num1 {int k=400;}
}
namespace {int j=500;}
void main()
{ cout<<“j=”<<num::j <<“ ”;
cout<<“k=”<<num::num1::k <<“ ”;
cout<<“j=”<<j <<“ ”;
}
OUTPUT
j = 200
k =400
j = 500
Explanation: In the above program, num and num1 are two namespaces. The num1 is declared inside the namespace num. The last namespace defined is the unnamed namespace. In function main(), the members of the namespaces are accessed using the scope access operator. The variable j is used in two different scopes.
21.18 Write a program to declare functions in namespace. Access the function in main().
#include<iostream>
using namespace std;
namespace fun
{
int add (int a, int b) {return (a+b);}
int mul (int a, int b); // prototype declaration
}
int fun :: mul (int a, int b) {return (a*b);}
int main()
{
using namespace fun;
cout<<“ Addition:” <<add(20,5);
cout<<“ Multiplication:” <<mul(20,5);
return 0;
}
OUTPUT
Addition : 25
Multiplication : 100
Explanation: In the above program, two functions add() and mul() are declared in namespace fun. In function main(), the statement using namespace fun allows us to access the elements of fun namespace directly. Two integer values are passed to the functions add() and mul(). They return the addition and multiplication of numbers, respectively.
21.19 Write a program to declare class in the namespace. Access the member functions.
#include<iostream>
using namespace std;
namespace clas_s
{
class num
{
private:
int t;
public:
num (int m)
{t=m;}
void show()
{cout<<“ t=”<<t; }
};
}
void main()
{
// indirect access using scope access operator
clas_s ::num n1(500);
n1.show();
// direct access using directive
using namespace clas_s;
num n2(800);
n2.show();
}
OUTPUT
t = 500
t = 800
Explanation: In the above program, class num is defined in the namespace clas_s. The class has one integer variable t and the member function show(). The member function show() displays the contents of the variable. In the function main(), n1 and n2 are objects of class num. The data members are initialized using a constructor. The members of class num are accessed with and without the scope access operator. Both the methods of accessing elements are explained in previous programs.
Alias means another name. A namespace alias is designed to specify another name to an existing namespace. It is useful if the previous name is long. We can specify a short name as alias and call the namespace members. The following program explains how an alias is specified:
21.20 Write a program to specify alias to existing namespace.
#include<iostream>
using namespace std;
namespace number
{
int n;
void show()
{cout<<“ n=”<<n;}
}
int main()
{
namespace num=number;
num::n=200;
number::show();
return 0;
}
OUTPUT
n=200
Explanation: In the above program, the namespace number is defined. In the function main(), its alias name is created as follows:
Namespace num=number;
The num is another name given to the namespace number. The member of the namespace number can be accessed using both the names, that is, num and number. The variable n is accessed using the name num, and the function show() is accessed using the name number.
We frequently use the statement using namespace std. This statement inserts a complete library in the current program. This is similar to including a header file, and the contents of the header file are available in the current program. We can access all classes, functions, and templates declared inside this namespace.
using namespace std;
As studied earlier, the above method of specifying namespace is called a using directive. The above declaration makes it possible to access all members of the namespace directly. All header files also use the namespace feature. If we include header files and namespace together in the same program, the variable declared in the header file will be global. Instead of the above declaration, you should observe the following declaration in order to prevent serious bugs. Consider the following program:
21.21 Write a program to access members of namespace std applying using declaration method.
#include<iostream>
int main()
{
int age;
std::cout<<“ Enter your age:”;
std::cin>>age;
std::cout<<“ Your age is:”<<age;
}
OUTPUT
Enter your age : 24
Your age is : 24
Explanation: In the above program, the 1 member of namespace std cannot be accessed directly. Consider the following statement:
std::cout<<“ Enter your age:”;
Here, the namespace name std is preceded by the object cout. In the same way, the cin object is accessed.
ANSI C++ has introduced various new keywords according to new characteristics of the language. The following table describes the keywords of both ANSI and Turbo C++:
Table 21.1 Keywords supported by ANSI and Turbo C++
(1) The Keyword pascal:
The keyword pascal is used to declare a variable or function using a Pascal-style naming convention:
Syntax:
pascal <data definition>;
pascal <function definition>;
In addition, pascal declares Pascal-style parameter-passing conventions when applied to a function header (first parameter pushed first; the called function cleans up the stack).
Examples:
int pascal x;
void pascal show(int x, int y);
21.22 Write a program to use pascal keyword and change the calling convention of C++ to pascal style.
#include<iostream.h>
#include<constream.h>
void main()
{
void pascal show (int,int);
int x=2;
show (++x,x);
}
void pascal show (int x, int y)
{
cout<<“ x=”<<x <<“ y=”<<y;
}
OUTPUT
x=3 y=3
Explanation: We know that in C/C++ the calling convention is from right to left; that is, the right most variable is first pushed in the stack. In order to replace this calling convention style with Pascal style, the keyword pascal can be used. This keyword is given in the prototype declaration and function declarator. When we pass an argument to this function, the calling convention will be from left to right. The calling conventions are described in Chapter 11.
(2) The Keyword cdecl
The keyword cdecl is used to declare a variable or a function in the C-style naming convention and pushes arguments in the stack in C-style parameter-passing conventions.
cdecl <data definition> ;
cdecl <function definition> ;
Example:
int cdecl l x;
void cdecl show(int x, int y);
21.23 Write a program to demonstrate the use of cdecl keyword.
#include<iostream.h>
#include<constream.h>
void main()
{
clrscr();
void cdecl show (int,int);
int x=7;
show (++x,x);
}
void cdecl show ( int x, int y)
cout<<“ x=”<<x <<“ y=”<<y;
}
OUTPUT
x=8 y=7
Explanation: The above program is similar to the previous one. Here, the keyword cdecl is used to apply the calling convention of C.
ANSI / ISO (“Include”) Files
The ANSI/ISO committee has introduced a new style for header files: the header file now without the extension .h.
Example
#include<iostream>
#include<vector>
In previous examples, we frequently used the header files given above. However, the conventional method <iostream.h> is also valid. A few header files are renamed; for example, <limit.h> with <climit>, math.h> with <cmath>, <stdio.h> with <cstdio>, and so on. Only a few names are listed in Table 21.2.
Table 21.2 ANSI/ISO header file names
C header files |
C++ header files(new style) |
---|---|
<cstring> |
<typeinfo> |
<ctime> |
<string> |
<cstdlib> |
<new> |
<cassert> |
<defines> |
<cctype> |
<sstream> |
<cerrno> |
<ostream> |
<cfloat> |
<iostream> |
<climits> |
<ios> |
<cmath> |
<iomanip> |
Turbo C++ Header (“Include”) Files
Table 21.3 contains a few frequently used names of header files of Turbo C++. The list is very exhaustive. You can view the complete list of header files through Help menu (contents option) present in Turbo C++ editor.
Table 21.3 Turbo C++ header files
iostream.h |
complex.h |
strstrea.h |
constream.h |
fstream.h |
bcd.h |
process.h |
generic.h |
string.h |
stdlib.h |
iomanip.h |
values.h |
math.h |
new.h |
float.h |
The C++ committee suggested keywords for operators, such as &&, ||. The keywords can be used in expressions instead of operators. Table 21.4 describes the operator keywords.
Table 21.4 C++ operator keywords
Operator |
Keyword |
---|---|
xor_eq |
^= |
xor |
^ |
or_eq |
|= |
or |
|| |
not_eq |
!= |
not |
! |
compl |
~ |
bitor |
| |
bitand |
& |
and_eq |
&= |
and |
&& |
(A) Answer the following questions
(B) Answer the following by selecting the appropriate option
(C) Attempt the following programs