Vous êtes sur la page 1sur 42

C++ SlidesContinued.

OVERLOADING CONCEPT If you specify more than one definition for a function name or an operator in the same scope, you have overloaded that function name or operator. CONCEPT If you call an overloaded function name or operator, the compiler determines the most appropriate definition to use by comparing the argument types you used to call the function or operator with the parameter types specified in the definitions. OVERLOADING FUNCTIONS You overload a function name f by declaring more than one function with the name f in the same scope. The declarations of f must differ from each other by the types and/or the number of arguments in the argument list.

When you call an overloaded function named f, the correct function is selected by comparing the argument list of the function call with the parameter list of each of the overloaded candidate functions with the name f. A candidate function is a function that can be called based on the context of the call of the overloaded function name.

EXAMPLE Consider a function print, which displays an int. you can overload the function print to display other types, for example, double and char*. You can have three functions with the same name, each performing a similar operation on a different data type:

#include <iostream> using namespace std; void print(int i) { cout << " Here is int " << i << endl;} void print(double f) { cout << " Here is float " << f << endl; } void print(char* c) { cout << " Here is char* " << c << endl; }

int main() { print(10); print(10.10); print("ten"); }

The following is the output of the above example: Here is int 10 Here is float 10.1 Here is char* ten EXAMPLE:Function Overloading #include<iostream.h> int area(float,float); int area(int,int,int); void main() { cout<<"AREA= "<<area(3.5,2.5)<<endl; cout<<"AREA= "<<area(3,7,5)<<endl; }

Overloading operators You can redefine or overload the function of most built-in operators in C++. These operators can be overloaded globally or on a class-by-class basis. Overloaded operators are implemented as functions and can be member functions or global functions.

An overloaded operator is called an operator function. You declare an operator function with the keyword operator preceding the operator. Overloaded operators are distinct from overloaded functions, but like overloaded functions, they are distinguished by the number and types of operands used with the operator. Operators valid for user defined classes & address-of operator = Assignment sizeof operator . Dot operator

Most of the other existing operators have no meaning for user defined classes. Designer of the class is the best person to define these operators (i.e. overloading)

Syntax Similar to a function with arguments and return type To overload the operator +: return_type operator + (arg-list) { operations to be performed } Rules for overloading Only valid C++ operators can be overloaded The operator precedence rule will remain as it is. The number of operands that an operator takes cannot be altered. For example, the overloaded + operator cannot have just one operand No default argument allowed in the function Operator function may be non-static member or a friend of the class. OVERLOADING A UNARY OPERATOR 1.There is only one operand to deal . 2.Operator function has no parameters if it is a member function . Overloading Unary Operator #include<iostream.h> class demo { int counter; public: demo() { counter=0; } int getcounter() { return(counter); }

void operator ++() { counter++; } }; void main() { demo d; cout<<d.getcounter(); d++; d++; cout<<d.getcounter();

Overloading Binary Operator Consider the standard + (plus) operator. When this operator is used with operands of different standard types, the operators have slightly different meanings. For example, the addition of two integers is not implemented in the same way as the addition of two floating-point numbers. C++ allows you to define your own meanings for the standard C++ operators when they are applied to class types. In the following example, a class called complx is defined to model complex numbers, and the + (plus) operator is redefined in this class to add two complex numbers.

// This example illustrates overloading the plus (+) operator #include <iostream> using namespace std;

class complx { double real, imag; public: complx( double real = 0., double imag = 0.); // constructor complx operator+(const complx&) const; // operator+() }; // define constructor complx::complx( double r, double i ) { real = r; imag = i; } // define overloaded + (plus) operator complx complx::operator+ (const complx& c) const { complx result; result.real = (this->real + c.real); result.imag = (this->imag + c.imag); return result; }

int main() { complx x(4,4); complx y(6,6); complx z = x + y; // calls complx::operator+() }

You can overload any of the following operators: Here () is the function call operator and [] is the subscript operator. You can overload both the unary and binary forms of the following operators You cannot overload the preprocessor symbols # and ##. An operator function can be either a nonstatic member function, or a nonmember function with at least one parameter that has class, reference to class, enumeration, or reference to enumeration type.

You cannot change the precedence, grouping, or the number of operands of an operator.

The operators new, delete, new[], and delete[] do not follow the general rules . All operators except the = operator are inherited.

EXAMPLE: #include<iostream.h> class complex { int real; int imag; public: complex(int i=0,int j=0):real(i),imag(j) { } friend complex operator+(complex&,complex&);

friend complex operator+(complex&,int); friend complex operator+(int,complex&);

void print() { cout<<real<<"+i"<<imag<<endl; } }; complex operator+(complex& c1,complex& c2) { return complex(c1.real+c2.real,c1.imag+c2.imag); } void main() { complex c1(2,3),c2(3,4); complex c3=c1+c2; c1.print(); c2.print(); c3.print(); }

Overloading Subscript operator When working with arrays, we typically use the subscript operator ([]) to index specific elements of an array: The subscript operator is one of the operators that must be overloaded as a member function. . However, consider the following IntList class, which has a member variable that is an array: 01 class IntList 02 { 03 private: 04 int m_anList[10]; 05 }; 06 07 int main() 08 { 09 IntList cMyList; 10 return 0; 11 }

Because the m_anList member variable is private, we can not access it directly from cMyList. This means we have no way to directly get or set values in the m_anList array. So how do we get or put elements into our list?

A better solution in this case is to overload the subscript operator ([]) to allow access to the elements of m_anList. The subscript operator is one of the operators that must be overloaded as a member function. In this case, our overloaded subscript will take one parameter, an integer value that is the index of the element to access, and it will return an integer. Example #include<iostream.h> class IntList { private: int m_anList[10]; public: int& operator[] (const int nIndex); };

int& IntList::operator[] (const int nIndex) { return m_anList[nIndex]; } int main() { IntList cMyList; cMyList[2] = 3; // set a value or setting element 2 to //the value of 3! cout << cMyList[2]; // get a value return 0; }

Advantage:Overloading [] The subscript operator is typically overloaded to provide access to 1-dimensional array elements contained within a class. Because strings are typically implemented as arrays of characters, operator[] is often implemented in string classes to allow the user to access a single character of the string. One other advantage of overloading the subscript operator is that we can make it safer than accessing arrays directly. Normally, when accessing arrays, the subscript operator does not check whether the index is valid. For example, the compiler will not complain about the following code: int anArray[5];

anArray[7] = 3; // index 7 is out of bounds! However, if we know the size of our array, we can make our overloaded subscript operator check to ensure the index is within bounds:

Overloading [ ] EXAMPLE: #include<iostream.h> class safearray { double* darray; int size; public: safearray(int i) { size=i; darray=new double[size]; }

double& operator [](int i) { return *(darray+i); } }; void main() { safearray s(50); for(int i=0;i<10;i++) s[i]=i+1; double d=s[5]; cout<<d<<endl; }

Output 6 Assignment Operator Assignment Operator The assignment operator (=) is, strictly speaking, a binary operator. Its declaration is identical to any other binary operator, with the following exceptions: assignment operator is used to copy the values from one object to another already existing object. Features

It must be a nonstatic member function. No operator= can be declared as a nonmember function.


It is not inherited by derived classes.

A default operator= function can be generated by the compiler for class types if none exists. Copy constructor and assignment operator The purpose of the copy constructor and the assignment operator are almost equivalent both copy one object to another. However, the assignment operator copies to existing objects, and the copy constructor copies to newly created objects. The difference between the copy constructor and the assignment operator If a new object has to be created before the copying can occur, the copy constructor is used. If a new object does not have to be created before the copying can occur, the assignment operator is used.

Three general cases where the copy constructor is called instead of the assignment operator: 1) When instantiating one object and initializing it with values from another object (as in the example above). 2) When passing an object by value. 3) When an object is returned from a function by value. In each of these cases, a new variable needs to be created before the values can be copied hence the use of the copy constructor. Because the copy constructor and assignment operator essentially do the same job (they are just called in different cases), the code needed to implement them is almost identical.

Overloading Assignment Operator #include <iostream> using namespace std; class alpha { private: int data; public: alpha(){ } alpha(int d){ data = d; }

void display() { cout << data; } alpha operator = (alpha& a) { data = a.data; cout << "\nAssignment operator invoked"; return alpha(data); } }; int main() { alpha a1(37); alpha a2; a2 = a1; cout << "\na2="; a2.display(); alpha a3 = a2; cout << "\na3="; a3.display(); cout << endl; return 0; }

Overload +,-,= relative to My class #include <iostream> using namespace std;


class MyClass { int x, y; public: MyClass() { x=0; y=0; } MyClass(int i, int j) { x=i; y=j; } void getXY(int &i, int &j) {

i=x; j=y; } MyClass operator+(MyClass object2); MyClass operator-(MyClass object2); MyClass operator=(MyClass object2); }; MyClass MyClass::operator+(MyClass object2){ MyClass temp; temp.x = x + object2.x; temp.y = y + object2.y; return temp; } MyClass MyClass::operator-(MyClass object2){ MyClass temp; temp.x = x - object2.x; temp.y = y - object2.y; return temp; } MyClass MyClass::operator=(MyClass object2) { x = object2.x; y = object2.y; return *this; // return the object that is assigned } int main() { MyClass object1(10, 10), object2(5, 3), object3; int x, y; object3 = object1 + object2; object3.getXY(x, y); // add two objects - //this calls operator+()

cout << "(object1+object2) X: " << x << ", Y: " << y << endl;

object3 = object1 - object2; // subtract two //objects object3.getXY(x, y); cout << "(object1-object2) X: " << x << ", Y: " << y << endl; object3 = object1; // assign an object object3.getXY(x, y); cout << "(object3=object1) X: " << x << ", Y: " << y << endl; return 0; }

INHERITANCE

Inheritance is a mechanism for enhancing the existing classes.

If a new class needs to be implemented and a class representing a more general concept is already available, then the new class can inherit from the existing class. The class inheritance relationship (is-a) Advantage of inheritance is code reusability

Base and Derived Classes The existing, more general class is called the base class.

class.

The more specialized class that inherits from the base class is called the derived

The derived class automatically inherits all member functions and data members of the base class. New member functions and data members can be specified in the derived class definition The constructor and destructor of a base class are not inherited the assignment operator is not inherited the friend functions and friend classes of the base class are also not inherited. Types of inheritance There are five types of inheritance.

1.Single Inheritance. 2.Multiple Inheritance. 3..Multilevel Inheritance. 4. Heirarchical Inheritance.

5.Hybrid Inheritance Single Inheretance Creating derived class from base class. Example:single inheretance #include<iostream.h>

class father { public:void f1() { cout<<"This is from class father"<<endl; } }; class mother:public father { public:void f2() { cout<<"This is from class mother"<<endl; } }; void main() { mother m; m.f1(); m.f2(); }

Multiple inheritance A class derived from more than one base class. class derived : public B1, public B2 , public B3 { }; Multiple Inheretance:Example #include<iostream.h>

class b1 { public:void f1() { cout<<"This is from class b1"<<endl; } }; class b2 { public:void f2() { cout<<"This is from class b2"<<endl; } }; class b3 { public:void f3() { cout<<"This is from class b3"<<endl; } }; class D:public b1,public b2,public b3 { public:void d1() { cout<<"This is from class derived"<<endl; } };

void main() { D dr_ob; dr_ob.f1(); dr_ob.f2(); dr_ob.f3(); dr_ob.d1(); }

Multilevel Inheritance

A derived class may be used as a base class for another derived class, creating a multilevel hierarchy. In this case, the original base class is said to be an indirect base class of the 2nd derived class. Multilevel Inheretance:Example #include<iostream.h> class b1 { public:void f1() { cout<<"This is from class b1"<<endl; } }; class b2:public b1 { public:void f2() { cout<<"This is from class b2"<<endl; } }; class b3:public b2 { public:void f3() { cout<<"This is from class b3"<<endl; } }; void main() { b3 b; b.f1(); b.f2(); b.f3(); }

Heirarchical Inheritance Here with a single base class is used for creating two or more derived classes .

The inheritance relationship can be shown as in the figure.

Hieararchiel Inheretance:Example #include<iostream.h>

class b1

{ public:void f1() { cout<<"This is from class b1"<<endl; } }; class b2:public b1 { public:void f2() { cout<<"This is from class b2"<<endl; } }; class b3:public b1 { public:void f3() { cout<<"This is from class b3"<<endl; } }; void main() { b2 b2_ob; b2_ob.f1(); b2_ob.f2(); b3 b3_ob; b3_ob.f1(); b3_ob.f3(); }

Hybrid Inheritance

A combination of two or more of the above mentioned inheritances.

EXAMPLE class rubber { protected: float thickness; char* grade; }; class wheel { protected: float radius; }; class tyre: public rubber,public wheel { protected: char* make; public: tyre(float t,char* g,float r,char* mk) { thickness=t; radius=r; grade=new char[strlen(g)+1]; strcpy(grade,g); make=new char[strlen(mk)+1]; strcpy(make,mk); } friend ostream& operator<<(ostream& ons,tyre& t) {

ons<<"\n"<<t.thickness<<"\n"<<t.grade<<"\n"<<t.radius<<"\n"<<t.make<<"\n"; return ons; }

};

void main() { tyre t(10.9,"A",4.5,"MRF"); cout<<t; }

Protected Members Member functions of derived class does not have access to the private members of the base class. To keep a member of a base class inaccessible to outside but still allow a derived class members to access it, is accomplished by the specifier protected. protected members of a class are accessible to members of any class derived from that base. Access Specifier class derived : access base ; Here access is one of three access specifiers : public or protected or private. public - all public members of the base become public members of the derived class. protected - all public members of the base become protected members of the derived class. private - all public members of the base class become private members of the derived class. In all cases, any private members of the base remain private to it and are inaccessible by the derived class. POLYMORPHISM Polymorphism One of the crucial features of OOPs.. Polymorphic - many forms C++ supports a mechanism known as virtual function to achieve polymorphism. It is also known as dynamic binding because the selection of the appropriate function is done dynamically at runtime Compile time polymorphism

Function overloading Operator overloading Polymorphism

Runtime

virtual functions

Object pointers are used to create objects at runtime to implement runtime polymorphism Dynamic Binding A base-class pointer can point to a derived class object.

A method invoked via base pointer might execute the method of the derived type . If the type changes during execution, so might the method selected .

Dynamic Binding Pointer or reference declared with one type may hold a variable of a derived type:

Dynamic type determined at run time

Can change during execution VIRTUAL FUNCTIONS Introduction C++ virtual function is a member function of a class, whose functionality can be over-ridden in its derived classes. The whole function body can be replaced with a new set of implementation in the derived class. The concept of c++ virtual functions is different from C++ Function overloading. C++ Virtual Function - Properties: C++ virtual function is,

A member function of a class Declared with virtual keyword Usually has a different functionality in the derived class A function call is resolved at run-time

The difference between a non-virtual c++ member function and a virtual member function is, the non-virtual member functions are resolved at compile time. This mechanism is called static binding. Where as the c++ virtual member functions are resolved during run-time. This mechanism is known as dynamic binding EXAMPLE #include<iostream.h> class base { public: void display() { cout<<"Display base"<<endl; } virtual void show()

{ cout<<"show base"<<endl; } }; class derived:public base { public: void display() { cout<<"Display Derived"; } void show() { cout<<"Show Derived"; } }; void main() { base b; derived d; base *basepointer; cout<<"base pointer points to base"<<endl; basepointer =&b; basepointer->display(); //calls base func basepointer->show(); //calls base func cout<<"base pointer points to derived"<<endl; basepointer=&d; basepointer->display(); //calls derived func basepointer->show(); //calls derived func }

C++ Virtual Function - Reasons:

The most prominent reason why a C++ virtual function will be used is to have a different functionality in the derived class. For example a Create function in a class Window may have to create a window with white background. But a class called CommandButton derived or inherited from Window, may have to use a gray background and write a caption on the center..

The Create function for CommandButton now should have a functionality different from the one at the class called Window C++ Virtual function - Example Assumes a base class named Window with a virtual member function named Create. The derived class name will be CommandButton, with our over ridden function Create. C++ Virtual function - Example #include<iostream.h> class Window // Base class for C++ virtual function //example { public: virtual void Create() // virtual function for C++ //virtual function example { cout <<"Base class Window"<<endl; } }; C++ Virtual function - Example class CommandButton : public Window { public: void Create() { cout<<"Derived class Command Button - Overridden C++ virtual function"<<endl; } };

C++ Virtual function - Example void main() { Window *x, *y;

x = new Window(); x->Create(); y = new CommandButton(); y->Create(); }

The output of the above program will be Base class Window Derived class Command Button If the function had not been declared virtual, then the base class function would have been called all the times. Because, the function address would have been statically bound during compile time. But now, as the function is declared virtual it is a candidate for run-time linking and the derived class function is being invoked. C++ Virtual function - Call Mechanism:

Whenever a program has a C++ virtual function declared, a v-table is constructed for the class. The v-table consists of addresses to the virtual functions for classes and pointers to the functions from each of the objects of the derived class. Whenever there is a function call made to the c++ virtual function, the v-table is used to resolve to the function address. This is how the Dynamic binding happens during a virtual function call. Abstract Class A class is an abstract class if it contains a pure virtual function. Provides an interface, but no behavior . Cannot be instantiated Used only as a base class for inheritance . Each derived class must have their own implementation of the virtual function.

Each level linked to the object above by a is-a relationship Each derived class is more specialized

Pure Virtual Function A pure virtual function is useful when we have a function that we want to put in the base class, but only the derived classes know what it should return. A pure virtual function makes it so the base class can not be instantiated, and the derived classes are forced to define these function before they can be instantiated. This helps ensure the derived classes do not forget to redefine functions that the base class was expecting them to. Interface class

An interface class is a class that has no members variables, and where all of the functions are pure virtual! Pure Virtual Function #include<iostream.h> class Base { public: virtual void do_something() = 0; }; class Derived1 : public Base { void do_something() { cout << "I'm doing something"; } };

class Derived2 : public Base { void do_something() { cout << "I'm doing something else"; } }; int main() { Base *pBase = new Derived1; pBase->do_something(); //does something delete pBase; pBase = new Derived2; pBase->do_something(); //does something else delete pBase; return 0; }

pBase uses the same interface (do_something ) but the result would vary depending on which derived class object you created. To access private data members of Derived through pBase ? You can access private members only on friend functions / classes. pBase would have access only to the members of Derived which are derived from Base. Example

Shape is an abstract class. class shape { public: //pure virtual function virtual double area ()=0; }; A class derived from an abstract class must implement the virtual function. class rectangle:public shape{ int l,b; public: rectangle(int len,int bred):l(len),b(bred){}; double area ( ){ return l * b;} }; class triangle : public shape { int b , h; public: triangle (int b1,int h1):b(b1),h(h1) { } double area() { return(0.5 * h * b ) ; } }; class circle : public shape { int rad; public: circle(int r):rad(r) { } double area() {

return 3.14 * rad * rad ;} }; void main() { shape *ptr[5]; ptr[0]= new rectangle(4,5); ptr[1] =new triangle(12,4); ptr[2] = new circle(6); for(int i=0;i <3;i++) cout<<ptr[i]->area()<<endl; }

TYPE CONVERSIONS IN C++ INTRODUCTION In C, assignments were generally of the kind lvalue = rvalue Where lvalue means Left Value and rvalue means Right Value. A left value is the place where the result is stored and the rvalue is the value to be stored.

With C++ this isn't quite so simple. The result of a function an lvalue or a rvalue depends on the following context If it is a reference then it's an lvalue, but anything else is an rvalue!

TYPE CONVERSIONS Changing a data type of a value is referred to as "type conversion".

There are two ways to do this: 1. Implicit the change is implied 2. Explicit the change is explicitly done with the cast operator

The value of a variable is stored as a sequence of bits, and the data type of the variable tells the compiler how to translate those bits into meaningful values. Often it is the case that data needs to be converted from one type to another type. This is called type conversion. Implicit type conversion is done automatically by the compiler whenever data from different types is intermixed.

When a value from one type is assigned to another type, the compiler implicitly converts the value into a value of the new type. For example: 1double dValue = 3; // implicit conversion to double value 3.0

2int nValue = 3.14156; // implicit conversion to integer value 3

The value being changed may be: 1. Promotion going from a smaller domain to a larger domain 2. Demotion going from a larger domain to a smaller domain

In the top example, the value 3 is promoted to a double value and then assigned to dValue. CONCEPT Definition 1: implicit A value that has its data type changed automatically. Definition 2: explicit Changing a value's data type with the cast operator. Definition 3: promotion Going from a smaller domain to a larger domain. Definition 4: demotion Going from a larger domain to a smaller domain.

Definition 5: truncation The fractional part of a floating-point data type that is dropped when converted to an integer. IMPLICIT TYPE CONVERSION Automatic conversion of a value from one data type to another by a programming language, without the programmer specifically doing so, is called implicit type conversion. It happens when ever a binary operator has two operands of different data types. Depending on the operator, one of the operands is going to be converted to the data type of the other. It could be promoted or demoted depending on the operator. EXAMPLE Implicit Promotion

55 + 1.75

In this example the integer value 55 is converted to a floating-point value (most likely double) of 55.0. It was promoted. EXAMPLE 2: IMPLICIT DEMOTION int money; // variable set up

then later in the program money = 23.16;

In this example the variable money is an integer. We are trying to move a floating-point value 23.16 into an integer storage location. This is demotion and the floating-point value usually gets truncated to 23. PROMOTION Promotion is never a problem because the lower data type (smaller range of allowable values) is sub set of the higher data type (larger range of allowable values). Promotion often occurs with three of the standard data types: character, integer and floating-point.

The allowable values (or domains) progress from one type to another.

That is the character data type values are a sub set of integer values and integer values are a sub set of floating-point values; and within the floating-point values: float values are a sub set of double.

Even though character data represent the alphabetic letters, numeral digits (0 to 9) and other symbols (a period, $, comma, etc.) their bit pattern also represent integer values from 0 to 255. This progression allows us to promote them up the chain from character to integer to float to double. EXPLICIT TYPE CONVERSION Most languages have a method for the programmer to change or cast a value from one data type to another; called explicit type conversion. Within C++ the cast operator is a unary operator; it only has one operand and the operand is to the right of the operator. The operator is a set of parentheses surrounding the new data type. Example: Explicit Demotion with Truncation (int) 4.234

This expression would evaluate to: 4.

TYPE CONVERSION Three Situations Built-in type to class type

Class type to Built-in type One class type to another class type.

Case-I Built-in to Class type ->Implemented using constructors. ->The constructor here takes a single argument, the type which is to be converted. Example: Converting a double type to a class type #include<iostream.h> class distance { int cm; int mm; public: distance(){ cm=0; mm=0; }

distance(float mts) { cm=mts*100; mm=mts*1000; } void show() { cout<<cm<<endl<<mm <<endl; } }; void main(){ distance d; float mtrs=12.3456; d=mtrs; d.show(); } Case-II Class to Basic type

Implemented using an overloaded casting-operator function. (Conversion Function) Syntax: operator typename() { Fn(statements) . return (basic type variable) } Converts a class type data to the basic type Example:class to basic #include<iostream.h> class distance { int cm; int mm; public: distance (){ cm=0; mm=0; }

distance(int a,int b){ cm=a; mm=b; } operator double() { double m; m=((cm/100)+(mm/1000)); return m; } }; void main() { distance d(1234,560); double n=d; cout<<n; }

Conditions for casting operator function 1.It must be a member function 2.It must not have any arguments. 3.It must not specify a return type. 4. It must return the basic type Case:III one class to another class Now that we have understood how to convert basic data types to class types and vice-versa, it is time to learn how to convert objects of one class type to another class type.

The conversion between objects of different classes can be done using either a one-argument constructor or a conversion function. The choice depends upon whether the conversion routine has to be declared in the source class or in the destination class.


To illustrate, consider a program that contains two classes: A and B. Also consider the statement: object_A = object_B;

In the above statement, object_B of type B is converted to type A and assigned to object_A. Therefore, object_B is the source and object_A is the destination.

For the conversion, the user can use either a conversion function or a constructor with one argument, depending on whether it is specified in the source class or the destination class. In other words, if class B handles the conversion, it will hold a conversion function. On the other hand, if class A carries out the conversion, it will do that through a constructor that takes an argument of type class B.

Class to class Summarizing:


class.

Implemented using a constructor or a type conversion function Constructor in the destination class (or) casting operator function in the source

In case of conversion ,constructor use special access functions in the source class for the data flow to the destination class. Class to class:Example #include <iostream> using namespace std; class Kilometers { private: double kilometers; public: Kilometers(double kilometers): kilometers(kilometers) {} void display() { cout << kilometers << " kilometeres"; } double getValue() { return kilometers; } };

class Miles { private: double miles; public: Miles(double miles) : miles(miles) {} void display() { cout << miles << " miles"; } operator Kilometers() { return Kilometers(miles*1.609344); } Miles(Kilometers kilometers) { miles = kilometers.getValue()/1.609344; } }; int main(void) {

/* * Converting using the conversion function */ Miles m1 = 100; Kilometers k1 = m1; m1.display(); cout << " = "; k1.display(); cout << endl;

/* * Converting using the constructor */ Kilometers k2 = 100; Miles m2 = k2; // same as: Miles m2 = Miles(k2); k2.display(); cout << " = "; m2.display(); cout << endl; }

Initialization lists C++ provides another way of initializing member variables that allows us to initialize member variables when they are created rather than afterwards. This is done through use of an initialization list. You could assign values to variables in two ways: explicitly and implicitly:

int nValue = 5; // explicit assignment double dValue(4.7); // implicit assignment Explicit assignment in the constructor body class Something { private: int m_nValue; double m_dValue;

int *m_pnValue; public: Something() { m_nValue = 0; m_dValue = 0.0; m_pnValue = 0; }

}; The same code using an initializer list: class Something { private: int m_nValue; double m_dValue; int *m_pnValue;

public: Something() : m_nValue(0), m_dValue(0.0), m_pnValue(0) { } };

The initialization list is inserted after the constructor parameters, begins with a colon (:), and then lists each variable to initialize along with the value for that variable separated by a comma. Note that we no longer need to do the explicit assignments in the constructor body, since the initializer list replaces that functionality. Also note that the initialization list does not end in a semicolon. Constructor with Base-Class Initializers CONSTRUCTORS & DESTRUCTORS The constructor of a derived class has to: Initialize the base object. Initialize its own data members. The base object is constructed with the default constructor of the base class. If the base class has no default constructor, then the base-class constructor is to be explicitly called in the derived-class constructor. A derived-class constructor must invoke the base-class constructor before initializing the derived-class data.

Constructor functions are executed in order of derivation. The destructor functions are executed in reverse order.

Constructor with Base-Class Initializers Calling Base-Class Member Functions When the base class and the derived class have a member function with the same name, must be more specific in the function call.Otherwise may have infinite recursion. EXAMPLE #include<iostream.h> #include<string.h> class employee { protected: char* name; double sal; int empid;

public: employee(char* ,double ,int ); employee(); void setdata(char* nm,double s,int id) { sal=s; empid=id; name=new char[strlen(nm)+1]; strcpy(name,nm); }

void print() { "<<empid<<endl; } };

cout<<"\nname "<<name<<"\nsalary "<<sal<<"\nemployee ID

employee::employee(char* nm,double s,int id) { sal=s; empid=id; name=new char[strlen(nm)+1]; strcpy(name,nm);

cout<<"\n constructor"; } employee::employee() { sal=0; empid=0; name=new char[1]; strcpy(name," "); }

class manager: public employee { double incentive; public: manager(double d) { incentive=d; }

manager(char* nm,double s,int id,int d):employee(nm,s,id) { incentive=d; }

void display() { print(); cout<<"incentive "<<incentive<<endl; } }; void main() { manager d("anu",1000,101,10); d.display(); }

Overloading >> and << operators The I/O Stream library overloads the left shift and right shift operators as insertion and extraction operators, respectively When creating your own classes it is usually more relevant to overload these operators as insertion and extraction operators

These overloaded operators cannot be defined as member functions They may be defined as global functions or friend functions.

Usually, these operators require access to private or protected data members of a class, therefore, they are usually defined as friend functions of the class

We can Overload >> and << to perform I/O for user defined types. For example if we have an object c1 of class complex,then we can display it through the statement

cout<<c1 or we can read it by saying cin>>c1 Achieving Overloading #include<iostream.h> class complex { private: double real,imag; public: complex() { }

complex(double r,double i) { real=r; imag=i; } friend ostream& operator <<(ostream& s,complex& c); friend istream& operator >>(istream& s,complex& c); }; ostream& operator<<(ostream& s,complex& c) { s<<"("<<c.real<<","<<c.imag<<")"; return s;

} istream& operator>>(istream& s,complex& c) { s>>c.real>>c.imag; return s; } void main() { complex c1(1.5,2.5),c2(3.5,4.5),c3; cout<<endl<<"c1="<<c1<<endl<<"c2="<<c2; cout<<endl<<"Enter a complex number:"; cin>>c3; cout<<"c3="<<c3; }

The statements cout<<endl<<"c1="<<c1<<endl<<"c2="<<c2; cout<<endl<<"Enter a complex number:"; cin>>c3; cout<<"c3="<<c3;

are much more expressive and are similar to the way we would perform I/O with standard types.

Here we have defined 2 friend functions operator<<() and operator>>(). Since the friend declarations of these functions occurs only in the complex class

And not in the istream or ostream classes these functions can access only the private data of complex class.

The operator functions are not members of the calss complex.

Hence the statement cin>>c3 doesnt get converted into the form cin.operator>>(c3)

The object on either side of>> gets passed to the oiperator function.

Both are collected as references. This prevents creation of copies of these objects. The comple object accesses the private data of complex class. The function returns the istream object by reference to permit cascading ,as in cin>>c4>>c5; Exactly the same argument applies to the operator <<() function. NAMESPACES Namespaces Consider the following 2 header files. //mylib.h char fun1(); void display(); class bignumbers{}; //somelib.h class bignumbers{}; void display(); If both these header files are included in a program;there would be a clash between the two bignumber classes and the two display() functions.

One solution to this could be to create long names such that there is a less likelihood of a clash. But then you are required to type these long names. It is compromise & not a language supported solution.

C++ offers a better solution to such problems through a keyword called namespace. C++ Provides a single global namespace. We can subdivide the global namespace into more manageable pieces using the namespace feature of c++. The following code shows how? //mylib.h namespace myheader { char fun1();

void display(); class bignumbers{}; } //somelib.h namespace somelib { class bignumbers{}; void display(); }

Now the class names will not clash bcoz they become mylib:: bignumbers and somelib::bignumbers,respectively. Same thing would happen to the function names.They would become mylib::display() and somelib::display(),thereby avoiding clash. Thus it is possible to use the same name in separate namespaces without conflict. FEATURES The syntax for creation of a nmaespace is similar to that of a class except for the semicolon beyond the closing brace. Declaration that fall outside all namespaces are still members of the global nmaespce.
A namespace definition can only appear at the global scope.Thus the following code would cause an error. void main() { namespace local //error: not a global scope { } } Using A Namespace There are 2 waysa to refer to a name with in a namespace:

a)Using the scope resolution operator b)Through the using Keyword Using the scope resolution operator #include<iostream.h> #include<string.h> namespace mine { class myclass { private:

int yr; public: void changeyear(); }; class yourclass; void fun1(); } void mine::myclass::changeyear() { yr=2000; cout<<"years don't change"; } class mine::yourclass { public: yourclass(); void show(); }; mine::yourclass::yourclass() { cout<<endl<<"Reached yourclass's zero-argument constructor"; } void mine::yourclass::show() { cout<<endl<<"Do it.Then don't think about it"; } void mine::fun1() { cout<<endl<<"Be impulsive.Excercise Caution"; } void main() { mine::myclass m; m.changeyear(); mine::fun1(); mine::yourclass y; y.show(); }

The using Keyword

Instead of being required to use the scope resolution operator before every nmae,the using keyword allows you to import the entire namespace at once. EXAMPLE #include<iostream.h> #include<string.h> namespace mine { class myclass { private: int yr; public: void changeyear(); };

class yourclass; void fun1(); } void mine::myclass::changeyear() { yr=2000; cout<<"years don't change"; } class mine::yourclass { public: yourclass(); void show(); }; mine::yourclass::yourclass() { cout<<endl<<"Reached yourclass's zero-argument constructor"; } void mine::yourclass::show() { cout<<endl<<"Do it.Then don't think about it"; }

void mine::fun1() { cout<<endl<<"Be impulsive.Excercise Caution"; } void main() { using namespace mine; myclass m; m.changeyear(); fun1(); yourclass y; y.show(); }

scope.

The using keyword declares all the nmaes in the nmaespace to be in the current

So we can use the names without any qualifiers.

Vous aimerez peut-être aussi