Sie sind auf Seite 1von 231

Programming in C++

Road Map

• Introduction to C++ Programming Language


– Introduction to historical program cycle of build
• A sample C++ program
• C styled C++, similarities and differences
• Inline functions and macros
• The variable argument list
• Namespaces
• The linkage specification: Using Extern
Road Map …

• Features of P/OOPS
• Classes, objects, methods, scopes, and inline nature
• Constructor and destructor
• Explicit constructor
• Copy constructor
• Default Object assignment and = operator
• Thumb Rules for class
• The constant functions and modification: mutable
• The static data and methods
• The early overloading: brief on ambiguity
• Pointers and references
Road Map …

• Overloading operators
• Communication
– Partial (Friend)
• Access and communication
– Complete (Inheritance)
• Reusability
• Virtual Inheritance and ambiguity with base class members
• Access control (Inheritance and protected members)
• Granting Access
• Virtual function, VTABLE, and pure virtual functions
– Inherited Virtual attribute, hierarchical
– The relation among classes and their behavior: A simple VTABLE
– Abstract classes (pure virtual function)
– Early binding vs. late binding
Road Map …

• Templates
– Generic function
– Generic Class templates
– Generic function and class restriction
– Explicit function and Explicit class specialization
– A brief on typename and export keywords
• Exception handling
– Fundamentals
– The try-catch, throw
– Multiple and Nested catches
– Catching class type exception
– Handling Derived class exceptions
– Catching all exceptions
– Terminate, unexpected, uncaught Exception function
Road Map …

• C++ File I/O


– Fstream and the File classes
– Opening and closing a file
– Reading and writing a text file
– Handling unformatted data
– Detecting EOF
– Random access and obtaining current file position
• RTTI
– Introduction to typeid
– Applying typeid to templates
– C++ typecast, Conversion function, Cast operators
• Dynamic_cast, constant_cast, Static_cast, reinterpret_cast
Introduction to language
WHAT IS A LANGUAGE?

• A language is someone’s response to a set of problems at


a given time.

• The problems and our understanding of solutions


change over time.

• A language lives and grows


C lovers
Think
Hard
Historical Notes

• C++ owes most to C. C++ 1987


– Other ancestors are Simula67 & Algol68.
• First versions of C++ in 1980 under the name “C
with classes”.
– Since 1983 the name C++ is used.
• 1990: ANSI/ISO 9899 defines a standard for C
• 1998: ISO/IEC 14882 specifies the standard for C++
C++ keywords

asm dynamic_cast namespace reinterpret_cast try

bool explicit new static_cast const_cast

catch false operator typeid using

delete inline private mutable template

class friend public this typename

Virtual true protected throw wchar_t


C++ keywords from C

auto const double float


int short struct unsigned
break continue else for
long signed switch void
case default enum goto
register sizeof typedef volatile
char do extern if
return static union while
Traditional Sample Program: Hello World

#include<iostream>
using namespace std; // c++ styled comments
int main()
{
cout<<“Hello World in C++”<<endl;
return 0;
}
More codes …
int accept()
{ char name[11]; int age
cout<<“Enter your name and age”;
cin>>name>>age;
return age;
}
int (*fun_handler)(); // a std c call is made as (*fun_handler)();
int main()
{
accept(); //direct calls
fun_handler=accept;
fun_handler() ; // it works from ANSI C
onwards, std C++ return 0;
}
Data’s Scope
int ivar=9;
int main()
{
int ivar=7;
{
int ivar = 5;
cout<<“Global scope ”<< ::ivar<<endl;
cout<<“Inner block ”<<ivar<<endl;
}
cout<<“Global scope ”<< ::ivar<<endl;
cout<<“Inner block ”<<ivar<<endl;
return 0;
}
No default to int
Fun(int ) ;
/* Defaults to integer return. Not to be used in standard C++.
Though, compilers takes it up as standard C / old C++ style
*/
int Fun(int); // should use this way
double Fun();
char *Fun();
double Fun( uiarg, siarg) // K&R style not allowed as std c++
unsigned uiarg;
int siarg;
Must use as done previous
Default value to arguments
int Fun(int x=4,int y=6) ; //controversial feature (do not use it)
Fun(); // 4,6
Fun(10); //10,6
Fun(10,20); // 10 , 20
--------------------------------------Case 1------------------------------------------------
-------------------------.h file-------------------------
int Fun(int x=4,int y=6) ;
-------------------------file that includes .h----------------
int Fun(int x=4,int y=0) ; // illegal, cant redefine
--------------------------------------Case 2------------------------------------------------
-------------------------.h file-------------------------
int Fun(int x=4,int y) ;
-------------------------file that includes .h----------------
int Fun(int x=4,int y=0) ; // allowed
Inline functions & macros
•Inline is a new storage class used in functions as if it were a
macro.
•Unlike a macro, an inline function does not have side effects.
For Example:
#define toupper(c) (islower(c) ? (c) + (‘a’ – ‘A’) : (c))
•When invoked with toupper(*p++) expands to
#define toupper(*p++) (islower(*p++) ? (*p++) + (‘a’ – ‘A’)
: (*p++)) and increments p twice.
An inline function does not exhibit this behavior. Looks as:
inline toupper(int ivar)
{return islower(c) ? c + (‘a’ – ‘A’): c;
} // invokes pointer only once
Inline functions & macros …

•Moreover as we have toupper as a function, the compiler can do


argument checking – impossible with a macro
•An inline function also solves the multiple line macro problem.
•You can’t do this with macro:
inline two_things()
{
int ret = a() ; b() ;
return ret ;
}
•Remember Inline is just a suggestion.
•Compiler might treat the function out of line.
Using namespace
#include<iostream>
using std::cout;
using std::cin;
using std::cerr;
using std::endl;
int main()
{ int ivar;
cout<<“using std namespace enter an integer ”<<endl;
cin>>ivar;
if(false) cerr<<“this message is going to err log.”<<endl;
return 0;
}
Using namespace …

// another way of representation


#include<iostream>
int main()
{
std::cout<<“Hello world”<<std::endl;
std::cin>>ivar;
if(false) std::cerr<<“this message is going to err log.”<<std::endl;
return 0;
}
Using namespace …

namespace rtos
{
int dontknow;
class MsgQ
{
char *message;
public:
MsgQ(){}
MsgQ(char *msg, int size);
};

}
Using namespace …

rtos::MsgQ::MsgQ(char *msg,int size)


{
message = new char[size+1];
message = msg ;
cout<<"Message [ "<<message<<" ] copied with [ "<<size<< " ]
bytes.\n";
}
Using namespace …
int main()
{
char *str = "Hello World.";
int len;
for(len=0; str[len]!='\0';len++);
rtos::dontknow = len; // this is how I know dontknow = len will not work
rtos::MsgQ mobj(str,rtos::dontknow);
using namespace rtos; // Mark this well
dontknow = 24;
MsgQ newobj("Bye Bye! cruel world :(",dontknow);
return 0;
}
Nested namespace …

A namespace should be globally declared exception to hide you namespace(s)


Example:
namespace RTOS { static int smp_w_lock;
namespace GPOS { static int named_pipes; // no of pipes used by
a task} }
Accessing named_pipes is:
RTOS::GPOS::named_pipes = 2 ; // default read/write channel to every
process
Or
using namespace RTOS; will allow
GPOS::named_pipes = 2;
Multiple declaration namespace …
•There may be more than one Namespace declaration of the same name.
•This allows it to be split over several files or even within the same file.
•For Example:
namespace RTOS { static int smp_w_lock;
……………}
namespace RTOS { static int no_of_current_task;
……………}
•This can be easily allowed and provide use of splitting heavy declarations;
•Accessing is as same way
int main(){ RTOS:: smp_lock == 5; // 5 processor now is using a w_lock
RTOS:: int no_of_current_task = 1; //ideal task is default
running} return 0;}
•A namespace must be globally declared (outside all the scope) exception is
nested namespaces as discussed earlier.
The linkage specification: Using Extern

•The extern keyword is extended from c, the only powerful keyword

•Allows the data, methods the files of same/different languages to


communicate

•It provides the true meaning of declaration too!

•No storage is done for data,methods of type extern.

•It needs to be redeclare/define somewhere else.

•This linker is supposed to know before it could create an executable image.

•Compiler simply ignore the extern statements


Using extern variable

//File: extern-scope.cpp //File memory-barrier.cpp


int *stack_signature = 0x1234; void* fix_stack_signature() {
extern int *stack_signature;
static int count;
while(count++ <= MAX_SIZE)
{
stack_signature++;
// rest of the code goes here
//….
return (void*)link;
}
main()
{
Ready to
linker Task
Run *task1=(task*)fix_stack_signature();
}
Using extern for Mixed language

•extern “C” void cfree(int*, char*) ;


•Describes compiler that this function is expanded under c and linkage
specification is to be made from it
• We can declare group of function together for the same

•extern “C” { void cfree(int*, char*);


int lock(Task *task);
………
}
•A statement like following is too! Legal and very useful

•extern “C” {
#include “c_extern_decl.h”
#include “f77_extern_decl.h”
}
P/OOPS Programming Concept

Classes, object, constructors,


Inheritance, Polymorphism,
Encapsulation, and Abstraction, …
P/OOP Concepts under C++ classes

Inheritance

Polymorphism
Objects
Objects

E n c a p s u l at i o n

Abstraction
Classes and objects
Classes and objects

Classes form the basis of object oriented programming


The class is used to express the nature of an object that would
result in existence
Thus, class is a logical abstraction
Why OOP not COP?
Well it’s the object that exists but what’s that
Everything is an object! Says Bruce Eckel!
Objects are real and they consume space
Classes and objects …
A class is a logical method to organize data and functions in the same structure.
They are declared using keyword class, whose functionality is similar to that of
the C keyword struct, but with the possibility of including functions as
members, instead of only data.
Its form is:
class class_name {
permission_label_1: member1;
permission_label_2: member2; ...
} object_name;
where class_name is a name for the class (user defined type) and the optional
field object_name is one, or several, valid object identifiers.
The body of the declaration can contain members, that can be
either data or function declarations, and optionally permission labels, that can
be any of these three keywords: private:, public: or protected:.
Classes and objects …

Class make reference to the permission which the following


members acquire:

•private members of a class are accessible only from other


members of their same class or from their "friend" classes.
•protected members are accessible from members of their
same class and friend classes, and also from members of their
derived classes.
•Finally, public members are accessible from anywhere the
class is visible.

If we declare members of a class before including any permission


label, the members are considered private, since it is the default
permission that the members of a class declared with the class
keyword acquire.
Classes and objects …
For example:
class CRectangle {
int x, y;
public:
void set_values (int,int);
int area (void);
} rect;
Declares class CRectangle and an object called rect of this class (type).
This class contains four members:
Two variables of type int (x and y) in the private section (because
private is the default permission) and two functions in the public
section: set_values() and area(), of which we have only included the
prototype.
Classes and objects …

On successive instructions in the body of the program we can refer to any


of the public members of the object rect as if they were normal functions
or variables, just by putting the object's name followed by a point and then
the class member (like we did with C structs).
For example:
rect.set_value(3,4);
myarea = rect.area();
but we will not be able to refer to x or y since they are private members of
the class and they could only be referred from other members of that same
class.
Let’s see a complete example of class CRectangle:
Classes and objects …
#include <iostream>
using namespace std;
class CRectangle {
int x, y;
int main () {
public:
CRectangle rect;
void set_values (int,int);
rect.set_values (3,4);
int area (void) {return (x*y);}
cout << "area: " << rect.area();
};
}
void CRectangle::set_values (int a, int b)
{
x = a;
y = b;
}
structures and classes are related

Structures are used same as classes but their access right


are public by default and private in class as default.
Struct can be used as classes:
Struct Human{private: int age;
public: char *nick_name;
protected: set_age();
}ram;

Now Human in a struct truly as a class.


unions and classes are related

Like structure, a union may also be used to define as class.


Union may contain methods and data members.
It may also contain constructor and destructors.
Like structures, union are also placed as public by default.
Anonymous Union
int main(){ union{
double dROI;
int iref_code;
char scmsg;};
dROI=000009.8125; // access as a variable
return 0;
}
Restrictions in Union

•A union cannot inherit any other classes of any type


•A union cannot be a Base class
•It cannot have virtual member functions
•Unions cannot have static data members
•Try above statements within your lab
Encapsulation

The least understood of the three concepts is encapsulation.

Sometimes, encapsulation is also called protection or information hiding.


In fact, encapsulation, protection and information hiding are three overlapping
concepts
Encapsulation is the inclusion within a program object of all the resources
need for the object to function - basically, the method and the data.

Other objects adhere to these interfaces to use the object without having to be
concerned with how the object accomplishes it.
Encapsulation …
An object can be thought of as a self-contained atom. The object interface consists of
public methods and instantiate data.

Protection and information hiding are techniques used to accomplish encapsulation of an


object.

Protection is when you limit the use of class data or methods.

Information hiding is when you remove data, methods or code from a class's public
interface in order to refine the scope of an object.

So, how are these three concepts implemented in C++?

You'll remember that C++ classes have a public, protected and private interface.

Moving methods or data from public to protected or to private, you are hiding the
information from the public or protected interface.
Encapsulation …
If you have a class A with one public integer data member d, then the C++
definition would be...
class Home
{
public:
integer doors;
};
If you moved that data member from the public scope of the private scope, then
you would be hiding the member. Better said, you are hiding the member from
the public interface.
class Home
{
private:
integer doors;
};
Constructors and destructors, const members,
copy constructors and default assignment
Constructors and destructors

Constructor:
•Constructors build objects from dust.
•Constructors are like "init functions". They turn a pile of
arbitrary bits into a living object.
•Minimally they initialize internally used fields. They may also
allocate resources (memory, files, semaphores, sockets, etc).
•"ctor" is a typical abbreviation for constructor.
Constructors and destructors …

•Destructors
•A destructor gives an object its last rites.
•Destructors are used to release any resources allocated by the
object.
•E.g., class Lock might lock a semaphore, and the destructor will
release that semaphore. The most common example is when the
constructor uses new, and the destructor uses delete.
•Destructors are a "prepare to die" member function. They are
often abbreviated "dtor".
Constructors and destructors …
class CRectangle {
int *width, *height;
public:
CRectangle (int,int);
~CRectangle ();
int area (void) {return (*width * *height);}
};
CRectangle::CRectangle (int a, int b) {
width = new int; height = new int;
*width = a; *height = b; }
CRectangle::~CRectangle () { delete width; delete height;}
int main () {
CRectangle rect (3,4), rectb (5,6);
cout << "rect area: " << rect.area() << endl;
cout << "rectb area: " << rectb.area() << endl; return 0;}
When are constructor and destructor executed?

•Important to note that they are implicit calls


•Compiler always includes one[Even if you do not]
•Constructors are called as the object is created
•Destructors are executed as reverse order of object creation
•Class CtorDtor{
pubilic:
CtorDtor(int ival) { cout<<ival<<“ctors “ <<endl;}
~CtorDtor(int ival) { cout<<ival<<“ctors “ <<endl;}
}g_of(1),g_os(2);
int main(){
CtorDtor l_of(3); cout<<“In main”<<endl;
CtorDtor l_of(4); return 0;
}
•What’s the order?
The Explicit keyword: avoiding default assignment
class Exp
{ int intCount;
public:
explicit Exp(int intTemp) {
intCount = intTemp ;
cout<<intCount<<endl;
}
Exp(int &intTemp) {
intCount = intTemp ;
cout<<intCount<<endl;
}
};
int main(){
Exp ExpObj (100) ;
Exp Exp_obja = 12 ; // not allowed to use default =
return 0; } // can be used for one parameterized cotrs
The default = operator
class Exp
{ int intCount;
public:Exp(){};
Exp(int intTemp) {
intCount = intTemp ;
cout<<intCount<<endl;
}
Exp(int &intTemp) {
intCount = intTemp ;
cout<<intCount<<endl;
}
};
int main(){
Exp ExpObj (100) ; Exp Exp_obja ;
ExpObj =Exp_obja; // calls default assignment =
}
The thumb rule for Class

A class should have a minimum two thumb rules

•A copy constructor
•An overloaded = operator
•We will look this further with operator overloads
The constant functions and modification: mutable

class Demo
{ //mutable int intVar; Allows const members to modify
int intVar;
public:
int getVar() const { return intVar*intVar;}
int setVar(int intLocal) const {intVar = intLocal;} // error try modifying
};
int main()
{
Demo demoObj;
demoObj.setVar(10);
cout<<"The value set is ="<<demoObj.getVar()<<endl;
return 0;
}
Sharing Data: static data, and methods
The static data and methods: shared data

Static data members and functions:


•When you are using a static variable you are saying compiler that
you will be using only one copy of it.
•In turn you are trying to use a shared resource
•Unlike other data members individual copies of static are not made
for each object.
•The data is assigned to 0 by default
•Declaration of static done within a class means a linkage
specification is needed ie; should be assigned with scope of class it is
assigned to.
•A static member exists before any object of its class is created.
•One of the typical Application of static is access control
The static data and methods: shared data

Static data members and functions:

•Methods too! Can be static

•There are several restrictions to this


•They may only directly refer to the other static members of class
•Global data and functions may be accessed by static methods
•No this pointer is associated with it
•It cannot be virtual
•Finally, they cant be const and volatile
An example: static data

Class Shared
{ public:
static int shared;
};
int Shared :: shared; // defaults to 0
int main(){
Shared::shared = 100; // accessing
Shared shared_obj;
shared_obj.shared ; // All class objects can use it too!
}
An example: resource allocation detail
Class SharedResource{ static int Resource;
public:
int getResource();
void freeResource(){Resource=0;}};
int SharedResource :: Resource;
void SharedResource::getResource(){
if(Resource) return 0;
else{
Resource=1; return 1;
}
int main(){ SharedResource task1, task2;
if(task1.getResource()) cout<<“task1 has resource”<<endl;
if(!task2.getResource()) cout<<“Resource busy”<<endl;
task1.freeResource();
if(task2.getResource()) cout<<“task1 has resource”<<endl;
task2. freeResource();
} // try a code to maintain the number of tasks currently being used
An example: static methods

class Sinit{
static int ival;
public:
static int f(int &temp)
{
ival=temp;
cout<<i<<endl;}
};
int Sinit::ival;
int main(void)
{
int ilocal=10;
Sinit::f(ilocal);
return 0;
}
Static/Early Overloading and ambiguities
Aspects of Overloading

•We have also observe that the default parameters can be very confusing.
But applications sometime needs that or sometimes we can use it as a
short hand for overloading
•Overloading is an alternative and respected answer default parameters
that provides the flexibility and convenience
•It also is towards the definition aspect for language as explains much
about the static aspects of polymorphism
•The secret of overloading is that each redefinition of the methods must
use either different type of parameters or the no. of parameters
•Overloads also leads to ambiguity at times.
Ambiguities under Overloading

•Example of a function overloaded


•int abs(float f) {return iabs>0?iabs:-iabs; };
•int abs(double d) {return iabs>0?iabs:-iabs; };

int main(){
abs(-100); // Ambiguous
abs(-100.05); // Unambiguous
}
Ambiguities under Overloading …

•Example of another function overloaded


•int f( char schar){ return schar;}
•int f( unsigned char uchar){ return uchar;}

int main(){
f(97); // Ambiguous
f(‘A’); // Unambiguous
}
Ambiguities under Overloading …

•Another way a function overloaded can cause ambiguity


•int f( int ivar){ return ivar;}
•int f( int ivar1, int ivar2=10){ return uchar;}

int main()
{
f(9); // Ambiguous
f(2,4); // Unambiguous
}
Ambiguities under Overloading …

•Another way a function overloaded can cause ambiguity


•int f( int &ivar){ return ivar;}
•int f( int ivar){ return ivar;} // error

int main()
{
int ivarl=100;
f(ivarl); // Ambiguous
}
Pointer, References and Dynamic memory
allocation
Pointer and References

Strict definition
•Pointers are cells (often present as two or four bytes) capable of
referencing and dereference the memory allocations
•References are alias to the variable, offers high performance code
play and regarded as true concept of C++
•Pointers can be used as indirect references

•Example:
•data_type *pointer ; // declaring a pointer
•data_type &reference = any_variable; // note the = is a must
Pointer and References

What is the difference between pointer and reference?(strong)

•Pointer can allocate memory at the run time.


•Reference cannot!
•They are just alias that are used to avoid formation
temporary data/objects copy
Pointer to objects

Class Ptr2O{ int ivar;


public: Ptr20(int temp) {ivar = temp;ip_var=temp;}
int get_val() {return ivar;}
int ip_var;
};
int main() {
Ptr20 obj(10) , *ptr;
ptr= &obj ;
cout<<ptr-> get_val()<<endl; // calls method
ptr=&obj.ip_var ; // only if public variable
cout<<*ptr<<endl;
}
Type checking C++ Pointers

int main() {
int *i_ptr;
float *f_ptr;
i_ptr = f_ptr ; // type mismatch
}
•C++ stronger type checking where pointers are involved, are different
from C, in which you may assign any value to any pointer.

•Though by casting it to the type is allowed but doing so is just by-passing


c++’s type check mechanism.
this pointer
•When a method is called, it is passed (a this pointer) as an implicit argument
that is a pointer to the invoking object. I.e.the object on which a method is
called.
•Theses type of pointer is called as [this pointer] represented as *this.
Example: class This{ int ivar;
public:
This (int itemp) { ivar = itemp;}};
Within a method ivar needs no object for access:
here ivar = itemp; means a copy of ivar associated with the
invoking object will be assigned the value containing itemp.
The statement can be rewritten as this->ivar = itemp; where this
pointer refers to that object’s ivar;
Nothing is gained by applying it explicitly and
hence use of this under such situation is useless. However this plays a very
important role under operator overloading as we will see later.
References

• As we know what reference is, the need to know is the three ways a
reference can be used

1. As a function parameter
2. As a function returning references
3. Independent references
Reference Parameters

void negate(int *itemp){ void negate(int &itemp){


*itemp = -itemp ; itemp = -itemp ;
}// manually }

int main()
{
int ilvar=1;
neg(&ilvar); // manual call via pointers
neg((ilvar); // no & requires
}
Note: Remember when you assign a value to reference, you are actually
assigning value to that variable what reference pointer points to.
Passing Reference to objects

Class Ref{ int id;


public: int ivar;
Ref (int temp){
cout<<“Constructing ”<<temp<<endl;
id = ivar ;
}
~Ref(){ cout<<“Destructing “<<id<<endl;}
void neg(Ref &r){
r.ivar = -r.ivar ; // No temporary object created
}
};
int main(){
Ref robj(1);
robj.ivar = 2;
robj.neg(robj);
cout<<o.i<<endl;
return 0;
}
Returning References
char str[]=“Hello World” ;
char &replace(int iposition)
{
return str[iposition] ;
}
int main(){
replace(5) = ‘Y’;
cout<<str<<endl;
return 0;
}
• Returning references allows function to be used on the left hand side as
shown above. A significant left function assignment
Independent References

• You can declare a reference that is simply a variable.

• This type of reference is called independent references.


Example:
int ival=10;
int &ref = ival;
ref = 11;
int b = 20;
ref = b ;
ref --; decrement b not ref
Restrictions to References

• You cannot reference another reference or say you cannot


obtain address of references
• You cannot create arrays of references
• You cannot create a pointer to a reference
• You cannot a reference bit
• A reference must be initialized when it is declared unless it
is a member of a class, function parameter, or a return value
• Null references are prohibited
C++ Dynamic Memory Allocation

• C++ provides dynamic memory allocation operators:


• new and delete
• The general forms of new and delete is as follows:
p_var = new type ;
delete p_var; //
• P_var is a pointer variable that receives a pointer to memory
that is large enough to hold an item of the type
• If new fails, an exception bad_alloc is thrown
• This exception is defined in <new>
• If exception handling is not handled program terminates
• New has been implemented differently over the time
C++ Dynamic Memory Allocation

• Initializing allocated memory:


• P_var = new var_type(initilizer);
• Allocating Arrays
• P_var = new array_type[size]
• delete [] p_var
• Allocating objects
• <Class name> p_var = new <Class name>
• Delete p_var;
C++ Dynamic Memory Allocation

• The nothrow Alternative: In std C++, it is possible


to have new return null instead of throwing an
exception while allocation fails.
• This is valuable when you are replacing old c
codes of malloc() with new.
• P_var = new (nothrow) type ;
Friends
Partial Communications:friend keyword

• Friend keyword add flexibility to the communication between two


different object. [typical example in overloading(coming up next)]
• It is possible to grant a non member function to the private members of a
class by using a friend
• Friend can be applied to
• Non member Methods
• Class
• It is you to decide the privacy rules as to allow a good friend!or not?
Friend function
class taskY; //Forward declaration
class taskX{ int current_stack_size;
public: taskX(int itemp){ current_stack_size = itemp;}
friend int total_stack_usage(task X, task Y)
};
class taskY{ int current_stack_size;
public: taskY(int itemp){ current_stack_size = itemp;}
friend int total_stack_usage(taskX , task Y)
};
int total_stack_usage(taskX xobj, taskY yobj)
{
return xobj.current_stack_size + yobj.current_stack_size ;
}
Friend function

int get_resource_size( ) { return 120;}


int main()
{
taskX taskx (get_resource_size());
taskY tasky (get_resource_size());
cout<< “ The total memory consumed by various tasks is: “;
cout<< total_stack_usage(taskx, tasky) <<endl;
}
Friend as classes: weak privacy
class pipes;
class Bucket{ char block_buffer[1501]; /1 eth packet payload
public: Bucket(){ block_buffer=‘\0’;};
void get_payload(char *buf)
{ strcpy(block_buffer,buf);}
friend class pipes;
};
class pipes{
char p_buf[2];
public: void read_char(Bucket);
};
void pipes:: read_char(Bucket bobj){
int i=0;
while( bobj.block_buffer[i] != ‘\0’){
p_buf[0]= bobj.block_buffer[i] ;
p_buf[1]=‘\0’;
Friend as classes: weak privacy

cout<<p_buf<<“ is transmitted serially!”<<endl;


} // work out this
int main()
{
Bucket bobj;
bobj.get_payload("Dummy payload packet");
pipes pobj;
pobj.read_char(bobj);
return 0;
}
Overloading operators
Overloading basics
• Class is an special user defined data type supporting OOP, no operators
except = is provided for objects. To gain we need to overload them.
• Almost all operators can be overloaded
• :: ?: . and .* are restricted for overloads
• This is useful for performing special job your class can operate
• Creating a member operator function
ret_type class_name::operator O(arg_list)
{
// operations
} where O is the place holder
ret_type is generally an object but can be any other too! if you need?
arg_list is empty if operator is unary, one if binary
Overloading operation: An complete Example

# include < iostream>


using namespace std ;

class loc {
int longitude, latitude ;

public :
loc () { } // needed to construct temporaries
loc (int lg, int lt) {
longitude = lg ;
latitude = lt ;
}
Overloading operation: An complete Example

void show () {
cout << longitude << “ “ ;
cout << latitude << “\n” ;
}

loc operator + (loc op2) ;


loc operator – (loc op2) ;
loc operator = (loc op2) ;
loc opertor ++ () ;
};
Overloading operation: An complete Example
// Overload + for loc.
loc loc : : operator + (loc op2)
{
loc temp ;
temp. longitude = op2.longitude + longitude ;
temp. latitude = op2.latitude + latitude ;
return temp;
} Note:
• + has one parameter as the operand on left side of the + is passed implicitly to the
function through *this pointer. The operand on the right is passed in the parameter
op2.
• The fact that the left operand is passed using *this implies one point: ie;
• When binary operators are overloaded, it’s the object on the left side that generates
the calls to the operator function
Overloading operation: An complete Example

// overload - for loc.


loc loc : : operator – (loc op2)
{
loc temp ;
// notice order of operands
temp. longitude = longitude – op2. longitude ;
temp. latitude = latitude – op2 . latitude ;
return temp ;
} in order to keep the meaning of subtraction, the operand on the right side of
the – is subtracted from left because it’s the object on the left that
generates the call to the operator-() function. Op2’s data must be
subtracted from the data pointed by *this.
• Remember always which operand generate calls to the function
Overloading operation: An complete Example

// over load assignment for loc.


Loc loc : : operator = (loc op2 )
{
longitude = op2.longitude ;
latitude = op2. latitude ;

return *this; // i.e., return object that generated call


}
• If c++ if = default overloaded. This is simply a member-by-member bitwise
copy.
• By overloading = you can alter the mechanism of it according to the
requirement that is generally not needed.
• The above is exactly what default does.
Overloading operation: An complete Example

// overload prefix ++ for loc.


Loc loc :: operator ++ ()
{
longitude ++ ;
latitude ++ ;
return *this ;
}
• Here, it takes no parameter.
Overloading operation: An complete Example
int main ()
{
loc ob1 (10, 20 ), ob 2 (5 , 30), ob 3 (90, 90) ;
ob1.show () ;
ob2.show () ;
++ ob1;
ob1.show () ; // displays 11 21
ob2 + ++ ob1 ;
ob1. show () ; // displays 12 22
ob2.show (0 ; // displays 12 22
ob1 = ob2 = ob3 ; // multiple assignment
ob1.show () ; // displays 90 90
ob2.show () ; // displays 90 90
return 0 ;
} // Avoid that would change the meaning of operator you loaded
Overloading operator using friend(flexibility)
class loc {
int longitude, latitude ;
public : loc () { }
loc (int lg, int lt ) {
longitude = lg ;
latitude = lt ;
}
void show () {
cout << longitude << “ “ ;
cout << latitude << “\n” ;
}
friend loc operator + (loc op1, int op2) ;
friend loc operator + (int op1, loc op2) ;
};
Overloading operator using friend(flexibility)

// + is overloaded for loc + int.


loc operator + (loc op1, int op2 )
{
loc temp ;

temp.longitude = op1. longitude + op2 ;


temp.latitude = op1. latitude + op2 ;

return temp ;
}
Overloading operator using friend(flexibility)

// + is overloaded for int + loc.


Loc operator + (int op1, loc op2 )
{
loc temp ;

temp. longitude = op1 + op2.longitude ;


temp. latitude = op1 + op2.latitude ;

return temp;
}
Overloading operator using friend(flexibility)

int main ()
{
loc ob1 (10, 20), ob2 (5, 30), ob3 ( 7 , 14) ;

ob1.show () ;
b2.show () ;
ob3.show () ;
ob1 = ob2 + 10 ; // both of these
ob3 = 10 + ob2 ; // are valid
ob1. show () ;
ob3.show () ;
return 0 ;
}
Overloading new and delete

class loc {
int longitude, latitude ;
public :
…. Other as previous
void *operator new (size_t size ) ;
void operator delete (void *p) ;
};
Overloading new and delete

// new overloaded relative to loc.


void *loc : : operator new (size_t size)
{
void *p ;
cout << “In overloaded new. \ n” ;
p = malloc (size) ;
return p ;
}
Overloading new and delete
// delete overloaded relative to loc.
void loc : : operator delete (void * p)
{
cout << “In overloaded delete . \n” ;
free ( p ) ;
}
int main ()
{
loc *p1, *p2 ;
p1 = new loc (10, 20) ;
p2 = new loc (-10, -20) ;
return 1 ;
}
Overloading Special operators []
class atype {int a [3] ; public :
atype (int i, int j, int k ) { a[ 0 ] = i ;
a[1]=j;
a[2] =k;
}
int operator [ ] (int i)
{ return a [ i ] ; }
};
int main ()
{
atype ob (1, 2, 3) ;
cout << ob [ 1 ] ; // displays 2
return 0 ;
}
Overloading Special operators ()
class loc {
int longitude, latitude ;
public :
loc (int lg, int lt) {
longitude = lg ;
latitude = lt ; }
void show () {
cout << longitude << “ “ ;
cout << latitude << “ \ n “ ;
}
loc operator + (loc op2) ;
loc operator () (int i, int j, )
};
Overloading Special operators ()

// Overload ( ) for loc.


loc loc : : operator () (int i, int j)
{
longitude = I ;
latitude = j ;
return * this ;
}
// Overload + for loc.
loc loc : : operator + (loc op2){ /*implement as earlier*/}
l
Overloading Special operators ()
int main ()
{
loc ob1 (10, 20) , ob2 (1, 1) ;

ob1.show ();
ob1 (7, 8) ; // can be executed by itself
ob1. show () ;

ob1 = ob2 + ob1 (10, 10) ; // can be used in expressions


ob1.show () ;

return 0 ;
}
Case of copy constructor/assignment

class eq
{
//int x;
public: int x;
eq(){}
eq(int temp)
{
x=temp;
cout<<"cons"<<x<<endl;
}
Case of copy constructor/assignment …
eq( const eq &e)
{
x =e.x;
cout<<"copycon"<<x<<endl;
}
eq &operator =(const eq &e)
{
x= e.x;
cout<<"= overload"<<x<<endl;
return *this;
}
~eq(){cout<<"des - called"<<endl;}
};
Case of copy constructor/assignment …
void f(eq &p)
{ cout<<"x= "<<p.x<<" @ "<<&(p.x)<<endl; }
int main()
{
eq o(10);
eq o1 = o; // invoke a copy constructor
eq o2 = o1; // invoke copy constructor
eq o3;
o3 = o2 = o1; // invoke = operator
f(o1); f(o2); f(o3);
return 0;
}
Complex declaration? [pointer to class members]
•Class Semaphore{ public: int lock;
Semaphore(int temp){ lock = temp;}
bool status_busy(){ lock>0?true:false;}
};
•Declaration of data member pointer
•int Semaphore::*lock_ptr;
•lock_ptr=&Semaphore:: lock; //get offset of data member
•Declaration of method member pointer
•bool (Semaphore::*status_ptr)();
•Status_ptr=&Semaphore::status_busy; //offset of method
•Calling is done as
•Semaphore Obj(1);
•If ((Obj.*status_ptr)()) cout<<“busy”<<endl; //method called
•Obj.*lock_ptr; // Is busy >0
[pointer to class members via pointer to object][ use ->*]

•Declaration of data/method member pointer


•int Semaphore::*lock_ptr;
•bool (Semaphore::*status_ptr)();
•Assignment
•lock_ptr=&Semaphore:: lock; //get offset of data member
•Status_ptr=&Semaphore::status_busy; //offset of method
•Calling is done as
•Semaphore Obj(1), *ptr;
•ptr= &Obj;
•ptr->*lock_ptr;
•(ptr->*status)();
Inheritance, Accessibility, virtual inheritance,
virtual functions, about vtable, and Abstract
classes
Inheritance

Inheritance is the concept that when a class of object is


defined, any subclass that is defined can inherit the definitions
of one or more general classes.

This means for the programmer that an object in a subclass


need not carry its own definition of data and methods that are
generic to the class (or classes) of which it is a part.

This not only speeds up program development; it also ensures


an inherent validity to the defined subclass object (what works
and is consistent about the class will also work for the
subclass).
Inheritance
The simple example in C++ is having a class that inherits a data member from its
parent class.
class A
{
public:
int d;
};
class B : public A
{
public:
};
The class B in the example does not have any direct data member does it?
It inherits the data member d from class A. When one class inherits from another, it
acquires all of its methods and data. We can then instantiate an object of class B and
call into that data member.
void func()
{
B b;
b.d = 10;
}
Inheritance
Class base{ int i,j;
public: void set(int a, int b) {i=a; j=b;}
void show(){ cout<<“i = ”<<i<<“ and j = ”<<j<<endl;}
};

Class derived:public base {};


// 1. Class derived:private base {};

int main(){
derived dobj;
dobj.set(12,15) ;
dobj.show() ;
}
/* if 1. Is uncommented following will not compile
int main(){
derived dobj;
dobj.set(12,15) ; //error
dobj.show() ; //error
} */
Inheritance and protected member
Class base{
protected: int i,j; //private to base
public: void set(int a, int b) {i=a; j=b;}
void show(){ cout<<“i = ”<<i<<“
and j = ”<<j<<endl;} };

Class derived: public base { int k;


public:
void setk(){ k= i * j ; //
derive can access i,j } void showk(){
cout<<“k in derived = ”<<k<<endl; }
};
int main(){
derived dobj;
dobj.set(12,15) ;
dobj.show() ;
Inheritance chain(level)
Class base{
protected: int i,j; //private to base
public: void set(int a, int b) {i=a; j=b;}
void show(){ cout<<“i = ”<<i<<“ and j = ”<<j<<endl;}
};

Class derived1: public base { int k;


public: void setk(){ k= i * j ; // derive can access i,j
} void showk(){ cout<<“k in derived1 =
”<<k<<endl; }
};
// i and j are inherited as public indirectly through derived1
Class derived2: public derived1 {int l;
public: void setl(){ l= i + j ; // derive can access i,j
} void showl(){ cout<<“l in derived2 =
”<<l<<endl; }
};
This will not compile …

Class base{
protected: int i,j; //private to base
public: void set(int a, int b) {i=a; j=b;}
void show(){ cout<<“i = ”<<i<<“ and j = ”<<j<<endl;} };

Class derived1: private base { int k;


public: void setk(){ k= i * j ; // derive can access i,j }
void showk(){ cout<<“k in derived = ”<<k<<endl; }
};
// i and j are inherited as public indirectly through derived1
Class derived2: public derived1 {int l;
public: void setl(){ l= i + j ; // cant access i,j }
void showl(){ cout<<“l in derived = ”<<l<<endl; }
};

Note: Even though base class is inherited as private by derived1, has the access to base’s public, and
protected member. But cannot pass this privilege to it’s derived
Protected base class inheritance
Class base{
protected: int i,j; //private to base
public: void set(int a, int b) {i=a; j=b;}
void show(){ cout<<“i = ”<<i<<“ and j = ”<<j<<endl;}
};
// all public n protected member of base becomes protected members of derived
Class derived1: protected base { int k;
public: void setk() { set(10,20); // may access i, j as eariler
k= i * j ; // derive can access i,j
}
void showk(){ cout<<“k in derived = ”<<k<<endl;
}
};
Class derived2: public derived1{};
main(){ derived1 d;
d.set(1,2); //illegal [is accessible if public]
return 0;
}
// if base class is inherited via protected, it means its members cannot be accessed
via out side function such as main() or any other independent function!
Granting Access

Class base{
protected: int i,j; //private to base
public: int public_var; // is public now
void set(int a, int b) {i=a; j=b;}
void show(){ cout<<“i = ”<<i<<“ and j = ”<<j<<endl;}
};

// making public variable private

Class derived1: private base {


public:
base:: public_var; //make public again
base::i; // not allowed
};
Note: Std c++ now has deprecated it. In future it may be replaced with using as per
documentation goes
Rough
Virtual base classes: virtual inheritance

A
iData

iData iData
?
B C
Compiler

D
Virtual base classes: virtual inheritance

The problem with the compiler is ambiguity


Allows multiple copies of member?
Problem:
1. What if we share it? [best solution]
2. What if we can manual access it [ :: needed]
1. Solution Is , inherit base class with a key word virtual
2. Dobj.C::iData = 12 ; (Dobj is D’s object) Or
Dobj.B::iData = 12 ; (Dobj is D’s object)
The second is a manual way but what if only one copy is
required?
goto 1.
Polymorphism

Inheritance is a very easy concept to understand. Polymorphism on the


other hand is much harder. Polymorphism is about an objects ability to
provide context when methods or operators are called on the object.

Polymorphism

In object-oriented programming, polymorphism (from the Greek meaning


"having multiple forms") is the characteristic of being able to assign a
different meaning to a particular symbol or "operator" in different contexts.
Polymorphism …
class C
{
class A {
public: public:
Virtual void f(){cout<<“A”<<endl;}
virtual void f()
};
{std::cout << "Hello from C" <<
class B : std::endl;};
{
};
public:
virtual void f() If I have an object A, then calling the
{ method f() will produce different results
std::cout << "Hello from B" << depending on the context, the real type
std::endl;}; of the object A.
};
func(A & a)
{ a.f();
};
Polymorphism …
Another growing concept in OOP is dynamic and static binding. Most languages provide
one or the other.

C++ provides both!

A method that is not virtual is said to be statically bound, whereas virtual methods are
said to be dynamically bound. Non-virtual methods are statically bound, because the
binding of the method is performed at compile and link time and cannot be changed.

Virtual methods are dynamically bound, because the binding of the method is actually
performed at run-time.

When you call a virtual method, a small lookup is performed in the object virtual table
(a.k.a. vtable) to find the address of the method being called. By manipulating an objects
vtable at run-time, the target address can be altered.
Vtable

It is the table compiler generate as a reference to loader/liker that make desion of


what offset to be selected.

Let’s understand through some case codes studies:

Vtable can be understood w.r.t two tables:

1. Code and call semantics


2. Data layout
Vtable
Table 1a: Example Code and Call Semantics

Call Entry-point
Declarations Call Callee
Adjustment Adjustment

struct A { pa->f() A::f() none none


virtual void f ();
virtual void g ();
virtual void h ();
int ia;
}; pa->g() A::g() none none
A *pa;

pa->h() A::h() none none


Vtable
struct B: public virtual A { pb->f() B::f() none None
void f ();
void h ();
int ib;
};
pb->A::f() A::f() none none

pb->g() A::g() none none

B *pb; pb->h() B::h() none none

A *pa_in_b = pb;
pa_in_b->f() B::f() none none

pa_in_b->g() A::g() none none

pa_in_b->h() B::h() none none

pa_in_b->A::f() A::f() none none


Example data layout

Table 1b: Example Data Layout

Declarations Size Offset Member

struct A { 0 A::vptr
virtual void f ();
virtual void g ();
virtual void h (); 16
int ia;
}; 8 ia

Note:
Each function descriptor in the vtable is 16 bytes but the offset and data pointers
are only 8, the earlier versions of this table didn't take that into account
struct B: public virtual A { 0 B::vptr
void f ();
void h ();
int ib;
};
8 ib

32
16 A::vptr

24 ia

struct C: public virtual A { 0 C::vptr


void g ();
void h ();
int ic;
};
8 ic

32
16 A::vptr

24 ia
Case study : Implementing a v-table

A()
B()
C()
Base-class
region Virtual function
Used by derived

Derived-class
region
User control area Compiler control area
Case study : Implementing a v-table …
typedef (*fp)();
Class Base{
int basedata; void Base__Base(){;;;;;;;;;;;;;;;}
public: int Base__A()(){/*----------*/}
Base(); int Base__B()(){/*----------*/}
virtual int A(); int Base__C()(){/*----------*/}
virtual int B(); int Base__D()(){/*----------*/}
virtual int C();
int Z(); fp virtual_Base[3] = //vfTab
}; {
Base__A,
Base::Base() {;;;;;;;;;;;;;;} Base__B,
int Base::A() { /*------*/} Base__C,
int Base::B() { /*------*/} };
int Base::C() { /*------*/}
int Base::Z() { /*------*/} struct class_Base
{
fp *vtab;
int basedata;
}
Case study : Implementing a v-table

struct class_Base s;
//Allocate space

Base__Base(&bobj)
//call constructor &s is the implicit
int main() this pointer
{
Base bobj; bobj.vtab = virtual_Base
bobj.Z();
bobj.A(); // Initialize a Vtab
} //the obj’s vft is initilized when the
object created –at run time. The major
diff b/w malloc and new

Base__Z(&s);

(*bobj.vtab[1])(&s)
Case study : Implementing a v-table
typedef (*fp)();
Class D:public Base{
int ddata; void D__D() {;;;;;;;;;;;;;;;}
public: int D__DA() {/*----------*/}
D(); int D_B() {/*----------*/}
virtual int DA(); //local B()
virtual int B();
}; fp virtual_D[3] = //vfTab
{
D::D() {;;;;;;;;;;;;;;} Base__A,
int D::DA() { /*------*/} D__B,
int D::B() { /*------*/} Base__C,
D_DA
};
struct class_D
{
fp *vtab;
int basedata;
int ddata;
}
Case study : Implementing a v-table: predict

Base *p = malloc(sizeof(D));
Base__Base(p) ;
int main()
D__D(p);
{
Base d = new D; p.vtab = virtual_D
d->B() ; // D’s vtab
}
//d->B
(*s.vtab[1])();
// does as the earlier but with D’s call
Problems with a default virtual in derived class

Class A { public: virtual void f() {printf(“A”);} };

Class B:A { public: void f() {printf(“B”);} };

Class C:B { public: void f() {printf(“C”);} };

void main(){
A *ap = new A; // works as expected
ap->f();
ap = new B;
ap->f(); // calls B::f()
ap = new C;
ap->f(); // calls C::F()

B *bp = new B; bp->f(); //calls B::f()

bp = new C;
bp->f(); // dosen’t work as expected: calls B::f() as p is a B ptr and c !virtual
}
Ending with Virtual destructors

class base{
public:
base(){}
~base(){}
}
class derived: public base{
public:
derived{}
~deriver(){}
}
int main()

{
base *b;
b = new derived;
delete b; // calls only base’s destructor as p is a base*[]

}
Abstraction
Another OOP concept related to encapsulation that is less widely used but
gaining ground is Abstraction.

Through the process of abstraction, a programmer hides all but the relevant data
about an object in order to reduce complexity and increase efficiency.

In the same way that abstraction sometimes works in art, the object that remains
is a representation of the original, with unwanted detail omitted. The resulting
object itself can be referred to as an abstraction, meaning a named entity made
up of selected attributes and behavior specific to a particular usage of the
originating entity.

The example presented is quite simple. Human's are a type of land animal and all
land animals have a number of legs.

The C++ definition of this concept would be...


Abstraction …
class LandAnimal
{
It can be said that the LandAnimal class
public:
was abstracted from the commonality
virtual int NumberOfLegs()=0;
between all types of land animals, or at
};
least those that I care about.
class Human : public LandAnimal
{ Other land animals can derive there
public: implementation from the same class.
virtual int NumberOfLegs()
class Elephant : public LandAnimal
{return 2;};
}; {
The method NumberOfLegs in
public:
LandAnimal is said to be a pure virtual
function. virtual int NumberOfLegs()
An abstract class is said to be any class {
with at least one pure virtual function.
return 4;
Here, we have created a class
};
LandAnimal that is abstract.
};
Abstraction …
Although we cannot create an instance of the class LandAnimal, we can pass
derived instances of the class to a common function without having to implement
this function for each type of LandAnimal.

bool HasTwoLegs(LandAnimal & x)


{
return (x.NumberOfLegs()=2);
};

There is also a less rigid definition of abstraction that would include classes that without
pure virtual functions, but that should not be directly instantiated.
A more rigid definition of abstraction is called purely abstract classes.

A C++ class is said to be purely abstract, if the class only contains pure virtual
functions.

The LandAnimal class was such a class. Purely abstract classes are often called
interfaces, protocol classes and abstract base classes.
Templates, generic function, class templates
and function templates
Templates

•Templates is C++ ‘s most sophisticated and high powered features

•Although not a part of original specification to C++, it was added several years
ago and is supported by all modern C++ compilers.

•Using templates it is possible to create generic function and classes

•In generic function or class the type of data upon which the function or class
operates is specified as a parameter

•Thus, we can use one function or class with several types of data without
recoding specific version of each of them
Generic function

•A generic function defines a general set of operation to various types of data

•A generic function is created using the keyword template.

•A normal meaning of template is seen as algorithm is independent of the data acting as a


framework on with any data may act.

•In essence, when you create a generic function you are creating a function that can
automatically overload itself. It’s general format is

Template <class type> <ret-type> fun-name(parameter list)


{
……..
}
Function template
# include<iostream>
using namespace std;

// This is a function template.


template <class X> void swapargs (X &a, X &b)
{
X temp;
temp = a;
a = b;
b = temp;

int main ( )
{
int i = 10, j = 20;
double x = 10.1, y =23.3;
char a = ‘x’, b = ‘z’;
Function template

cout << “Original i, j:” << i <<’ ‘ << j << ‘\n’;


cout << “Original x, y:” << x <<’ ‘ << y << ‘\n’;
cout << “Original a, b:” << a <<’ ‘ << b << ‘\n’;

swaprgs (i, j); // swap integers


swaprgs (x, y); // swap floats
swaprgs (a, b); // swap chars

cout << “Swapped i, j:” << i <<’ ‘ << j << ‘\n’;


cout << “Swapped x, y:” << x <<’ ‘ << y << ‘\n’;
cout << “Swapped a, b:” << a <<’ ‘ << b << ‘\n’;

return 0;
}
Remember

// This will not compile. // This will

template <class X> template <class X>


int i;
void swapargs (X &a, Z &b) void swapargs (X &a, X&b)
{ {
X temp; X temp;

temp = a; temp = a;
a = b; a = b;
b = temp; b = temp;
} }
A function with two generic type

# include <iostream>
using namespace std;

template <class type1, class type2>


void myfunc (type1 x, type2 y)
{
cout << x << ‘ ‘ << y << ‘\n’;
}

int main ( )
{
myfunc (10, “I like C++”);
myfunc (98.6, 19L);
return 0;
}
Explicitly overloading a generic function

// Overriding a template function


# include <iostream>
using namespace std;
template <class X> void swapargs (X &a, X &b)
{
X temp;

temp = a;
a = b;
b = temp;
cout << “Inside template swapargs.\n”;
}
Explicitly overloading a generic function

// This overrides the generic version of swapargs ( ) for ints.

void swapargs (int &a, int &b)


{
int temp;

temp = a;
a = b;
b = temp;
cout << “Inside swapargs int specialization.\n”;
}
Explicitly overloading a generic function

int main ( )
{
int i = 10, j = 20;
double x = 10-.1, y = 23.3;
char a = ‘x’, b = ‘z’;
cout << “Original i, j:” << i <<’ ‘ << j << ‘\n’;
cout << “Original x, y:” << x <<’ ‘ << y << ‘\n’;
cout << “Original a, b:” << a <<’ ‘ << b << ‘\n’;
swapargs (i, j); // calls explicitly overloaded swapargs ( )
swapargs (x, y); // calls generic swapargs ( )
swapargs (a, b); // calls generic swapargs ( )
cout << “Swapped i, j:” << i <<’ ‘ << j << ‘\n’;
cout << “Swapped x, y:” << x <<’ ‘ << y << ‘\n’;
cout << “Swapped a, b:” << a <<’ ‘ << b << ‘\n’;
return 0;
}
Using Standard Parameters with Template Functions

const int TABWIDTH = 8;

// Display data at specified tab position.


template <class X> void tabout (X data, int tab)
{
for (; tab; tab--)
for (int i = 0; i<TABWIDTH; i++) count << ‘ ‘;`
cout << data << “\n”;
}
int main ( )
{
tabout (“This is a test”, 0);
tabout (100, 1);
tabout (‘X’, 2);
tabout (10/3, 3);
return 0;
}
Generic Function Restrictions
void myfunc (int i) {
cout << “value is: “ << i << “\n”;
}
void myfunc (double d)
{
double intpart;
double fracpart;
fracpart = modf (d, &intpart);
cout << “Fractional part: “ << fracpart;
cout << “\n”;
cout << “Integer part: “ << intpart;
}
int main ( )
{
myfunc (1);
myfunc (12.2);
return o;
} // templates cannot be applied for such situation as variant nature of a
fun.
Class templates

const int SIZE =10;

\\ Create a generic stack class


template <class StackType>
class stack
{
StackType stck [SIZE]; // holds the stack
int tos; // index of top-of-stack

public :
stack ( ) { tos = 0; } // initialize stack
void push (StackType ob); // push object on stack
StackType pop ( ); // pop object from stack
};
Class templates …

// Push object.
template <class StackType> void stack <StackType>:: push
(StackType ob)
{
if (tos = =SIZE) {
cout << “Stack is full./n”;
return;
}
stck [tos] = ob;
tos++;
}
Class templates …

// pop an object.
template <class StackType>StackType stack<StackType> : : pop (
)
{
if (tos = = 0) {
cout << “Stack is empty./n”;
return 0; // return null on empty stack
}
tos--;
return stck [tos];
}
Class templates …
int main ( )
{
// Demonstrate character stacks.
stack<char> s1, s2; // create two character stacks
int i;

s1.push (‘a’); s2.push (‘x’);


s1.push (‘b); s2.push (‘y);
s1.push (‘c’); s2.push (‘z);

for (i=0; i<3; i++) cout << “Pop s1: “ <<s1.pop( ) << “\n”;
for (i=0; i<3; i++) cout << “Pop s2 “ <<s2.pop( ) << “\n”;

// demonstrate double stacks


stack<double>ds1, ds2; // create two double stacks

ds1.push (1.1); ds2.push (2.2);


ds1.push (3.3); ds2.push (4.4);
ds1.push (5.5); ds2.push (6.6);

for (i=0; i<3; i++) cout << “Pop ds1: “ << ds1.po. ( ) << “ /n”;
for (i=0; i<3; i++) cout << “Pop ds2: “ << ds2.po. ( ) << “ /n”;
return 0;
}
The typename keyword

•Recently these two keywords have been added to C++


specifically to templates.

•The typename has two use

•It can be substituted for the keyword class in template


declaration

•Another is: It informs compiler that the name is being


used in a template declaration is a type rather than an
object name.
Example

template <typename X> void swapargs (X &a, X &b)


{
X temp;

temp = a;
a = b;
b = temp;
}
Exception Handling
Exception Handling: Fundamentals

•Exception handling allows you to manage run-time errors

•The principal advantage of EH is that it automates much of the error


handling code that previously had to be coded in hand

•C++ exception is built upon three keywords


•Try
•Throw
•Catch
•Try is the block where you will/can monitor your programs

•If an exception occurs, it is thrown using throw

•The exception is caught using the catch() and processed

•Try should have a catch() immediately after the try’s block


Exception Handling: Fundamentals
Exception Handling …
•The generic form of it:

try{
// possibly expecting an error
if the expected
throw list-type;
}
// int x; will not work
catch(type list)
{

}
•Can have nested catches
Try
{ ……….}
catch(type1 list)
{ }
Catch(type2 list)
{ }
A simple example
# include <iostream>
using namespace std;

int main ( )
{
cout << “Start\n”;

try { // start a try block


cout << “Inside try block\n”;
throw 100; // throw an error
cout << “This will not execute”;
}
catch (int i) { // catch an error
cout << “Cought an exception – value is: “;
cout << i << “\n”;
}
cout << “End”;
return 0;
}
Multiple catches

try { // start a try block


cout << “Inside try block\n”;
throw 100; // throw an error
cout << “This will not execute”;
}
catch (int i) { // catch an error
cout << “Cought an exception – value is: “;
cout << i << “\n”;
}
catch (float i) { // catch an error
cout << “Cought an exception – value is: “;
cout << i << “\n”;
}
catch (char * i) { // catch an error
cout << “Cought an exception – value is: “;
cout << i << “\n”;
}
Multiple catches
void Xhandler (int test)
{
try {
if (test) throw test;
else throw Value is zero”;
}
catch (int i) {
cout << “Caught Exception #: “ << i << ‘\n’;
}
catch (const char *str) {
cout << “Caught a string: “;
cout << str << ‘\n’;
}}

int main ( )
{
cout << “Start\n”;
Xhandler (1); Xhandler (2); Xhandler (0); Xhandler (3);
cout << ‘End”;
return 0;
}
Exception Handling…

•You can can any type of exception you want


•Its general form is:
Try
{

}
Catch(…){
// any exception un-handled type will come here
}
•You can re-throw an exception to outer block seeking if that can handle
•It’s general form is
Try
{
try{
if problem then
throw
}
catch(type list) {
// I will not /cannot handle hence
throw list
}}
Catch(…) {}
Example: Catch Any type …

Int main()
{
try {

}
catch(…)
{
cout<<“Any thin will come here”;
}

}
Throwing an exception from a function outside the try block.

void Xtest (int test)


{
cot << “Inside Xtest, test is: “ << test << “\n”;
if (test) throw test;
}

int main ( )
{
cout << “Start\n|;
try { // start a try block
cout << “Inside try block\n”;
Xtest (0);
Xtest (1);
Xtest (2);
}
catch (int i) { // catch an error
cout << “Caught an exception – value is: “;
cout << i << “\n”;
}
Restricting Exception Handling…
•You can restrict an exception that a function can throw outside itself

•Its general form is

<ret_type> <fun_name> (arg-list) throw (int, char*)


{
// handles only whole numbers and strings

}
•Note:
•if you throw any other type of exception then abnormal program
termination would occur that internally calls a function unexpected()
which by default calls terminate()

•This restrictions apply only when you throw an exception outside a


function. You may have inner try..catch within your function

•You can similarly handle your own class type for all the above explained
concept
Restricting function throw types.

// This function can only throw ints, chars, and doubles.


void Xhandler (int test) throw (int, char, double)
{
if (test ==0) throw test; // throw int
if (test ==1) throw ‘a’; // throw char
if (test ==2) throw 123.23; // throw double
}

int main ( )
{
cout << “Start\n”;
Restricting function throw types.

try{
Xhandler (o); // also, try passing 1 and 2 to Xhandler ( )
}
catch (int i) {
cout << “Caught an integer\n”;
}
catch (char c) {
cout << “Caught char/n”;
}
catch (double d) {
cout << “Caught double /n”;
}
Setting the terminate

void my_Thandler()
{
cout<<"in my terminate"<<endl;

}
int main()
{
set_terminate(my_Thandler);

try{
if something wrong
throw ;
}
catch(type list)
{// catch a type
}
File Handling in C++
Hierarchy

IOS

istream ostream

iostream fstreambase

ifstream ofstream

FSTREAM
Operation under a file

•A file is a collection of data stored with the secondary physical media.

•The data storage differs in media and the standard file and I/O
libraries takes care of bringing in to main memory[RAM] area.

•This is the place data can be read,written, modified, appended, and


deleted.

•Accessing a file is done internally via device pointers that is


maintained by system calls or device specific calls implemented under
the OS you use.

•These system calls are the wrappers build around those system calls
that allow primarily the file operation you need to perform.

•The I/O initialization is the most challenging job that provide a


channel for open and close for any operation on file you want.
Operation under a file …

•The file handling of C as we know is very powerful and based on its


strength of library its widely popular and known to almost every one.

•C++ behaves a bit differently as it deals with object behavior and tries
to provide a easy way of handling file too!

•C++ provides set of manipulation on data related to formatting stuff

•You can do operations on both the types of data


•Formatted (generally ASCII files are in this use)
•Unformatted (Binary / raw data (no formatting present data)

•You can use <fstream> header for file based manipulation

•For standard c++ I/O <I/Ostream> also is used


The first program

#include <fstream>
using namespace std;

int main()
{
ofstream SaveFile("cpp-file.txt");
//an object with constructor

SaveFile << "Hello World!\n";


// writing via obj and << (default overloaded)

SaveFile.close();
// calling close method to free the file descriptor
return 0;
}
Reading A File

#include <fstream.h>

void main() //the program starts here


{
ifstream OpenFile("cpp-file.txt");

char ch;
while(!OpenFile.eof())
{
OpenFile.get(ch);
cout << ch;
}
OpenFile.close();
}
//The function eof() returns a nonzero value if the end of the file has
been reached. So, we make a while loop, that will loop until we
reach the end of the file
A useful reading

#include <fstream.h>

void read(ifstream &T) //pass the file stream to the


function
{
//the method to read a file, that I showed you before
char ch;

while(!T.eof())
{
T.get(ch);
cout << ch;
}

cout << endl << "--------" << endl;


}
A useful reading …

void main()
{
ifstream T("file1.txt");
read(T);
T.close();

T.open("file2.txt");
read(T);
T.close();
}
Modes of operation
ios::in Open file to read

ios::out Open file to write

ios::app All the date you write, is put at the end


of the file. It calls ios::out
ios::ate All the data you write, is put at the end
of the file.

ios::trunc Deletes all previous content in the file.


(empties the file)
ios::nocreate If the file does not exists, opening it with
the open() function gets impossible.

ios::noreplace If the file exists, trying to open it with


the open() function, returns an error.

ios::binary Opens the file in binary mode.

In fact, all these values are int constants from an


enumerated type. But for making your life easier, you can
use them as you see them in the table.
Using modes file I/O

#include <fstream.h>

void main()
{
ofstream SaveFile("file1.txt", ios::ate);

SaveFile << "That's new!\n";

SaveFile.close();
}

Note: If you want to set more than one open mode, just use the OR
operator- |.

This way: ios::ate | ios::binary


Read/Write at once
#include <fstream.h>

void main()
{
fstream File("test.txt",ios::in | ios::out);

File << "Hi!"; //put “Hi!” in the file


static char str[10];
//when using static, the entire array is 0

File.seekg(ios::beg); //get to the beginning of file


//seekg(-5) will take u 5 char back
//this function is because default overloaded >> operator
File >> str;
cout << str << endl;
File.close();
}
Seekg is overloaded hence File.seekg(-5,ios::end);
Reading word by word

char str[30];

//the word can’t be more than 30 characters long

while(!OpenFile.eof())
{
OpenFile >> str;
cout << str;
}
Reading line by line

char line[100]; //a whole line will be


stored here
while(!OpenFile.eof())
{
OpenFile.getline(line,100);
//where 100 is the size of the array
cout << line << endl;
}
Check if the file opening was successful or not

Example 1: The most usual way

Xfstream File(“cpp-file.txt”); //X=i/o


if (!File)
{
cout << “Error opening the file! Aborting…\n”;
exit(1);
}
Check if the file opening was successful or not

Example 2: If the file is created, return an error

ofstream File("unexisting.txt", ios::nocreate);

if(!File)
{
cout << “Error opening the file! Aborting…\n”;
exit(1);
}
Check if the file opening was successful or not

Example 3: Using the fail() function

ofstream File("filer.txt", ios::nocreate);

if(File.fail())
{
cout << “Error opening the file! Aborting…\n”;
exit(1);
}

The new in Example 3, is the fail() function. It returns a


nonzero value if any I/O error (not end of file) has occurred.
Handling Binary data [byte by byte]
Example 1: Using get() and put()

#include <fstream.h>

void main()
{
fstream File("test_file.txt",ios::out | ios::in | ios::binary);

char ch;
ch='o';

File.put(ch); //put the content of ch to the file

File.seekg(ios::beg); //go to the beginning of the file

File.get(ch); //read one character

cout << ch << endl; //display it

File.close();
}
Handling Binary data [block-wise data]
Example 2: Using read() and write()

#include <fstream.h>
#include <string.h>

void main()
{
fstream File("test_file.txt",ios::out | ios::in | ios::binary);
char arr[13];
strcpy(arr,"Hello World!"); //put Hello World! into the array
File.write(arr,5);
//put the first 5 symbols into the file- "Hello"

File.seekg(ios::beg); //go to the beginning of the file


static char read_array[10]; //I will put the read data, here

File.read(read_array,3); //read the first 3 symbols- "Hel"

cout << read_array << endl; //display them


File.close();
}
Some useful functions

tellg() - Retunrs an int type, that shows the current position of the
inside-pointer. This one works only when you read a file.

tellp() - The same as tellg() but used when we write in a file.

seekp() - Remember seekg()? we used it, when we was reading a


file, and I wanted to go to specified position. seekp() is the same,
but it is used when you write in a file.

ignore(int count,char delimeter) - Used when reading a file. If you


want to ignore certain amount of characters, just use this function.

_unlink() - Deletes a file. Include io.h in your program, if you are


going to use this function.
Creating you own inserters and extractors

Inserters general form is:

ostream &operator<<(ostream &stream, class_type type)


{
//…
return stream; //should always return
}

Extractors general form is:

istream &operator>>(istream &stream, class_type type)


{
//…
return stream; //should always return
}
Example

Class phonebook{
public:
char name[80];
int areacode;
int prefix;
int num;
phonebook( char*n, int ac, int p, int nu)
{
strcpy(name,n);
areacode = ac;
prefix = p;
num = nm;
}
friend ostream &operator <<(stream &stream,phonebook o);
friend ostream &operator >>(stream &stream,phonebook &o)

};
Example …

ostream &operator <<(stream &stream,phonebook o)


{
stream<<o.name<<“ “;
stream<<“( “<<o.areacode<<“ ) “;
stream<<o.prefix<<“- “;
stream<<o.num<<endl;
}

istream &operator >>(stream &stream,phonebook &o)


{
cout<<“Enter a name: ”; stream>>o.name ;

cout<<“Enter a areacode: ”; stream>>o.areacode ;

cout<<“Enter a prefix: ”; stream>>o.prefix ;

cout<<“Enter a number: ”; stream>>o.num ;


return stream;
}
Example …

int main()
{
phonebook a;

cin>>a;
cout<<a;

return 0;
}
Run time type identification
type_id, cast operators
RTTI

•C++ now supports RTTI and cast_operators.

•Under nonpolymorphic languages it is not needed such as C.

•RTTI were not the specification of STD C++ but both were added
to C++

•The deterministic behavior of the calls under polymorphism is


known under RTTI.

•To obtain an obj’s type, we can use typeid.

•Use <typeinfo> to use the typeid


•Typeid(object)
•Typeid returns an reference to an object of type type_info that
describes the type of object
typeid …

•The type_info class has following public members

•bool operator ==(const type_info &obj);


•bool operator !=(const type_info &obj);
•bool before(const type_info &obj);
•bool char *name()

•The 1st two are for comparison operator for object similarity check

•The before returns true if the invoking object is before the object
used as a parameter in calling order.

•Name() returns a pointer to the name of the type


typeid …

int main()
{
int i,j;
float f;
char *p;
Base bob;
Derived dob;
printf("typeid of i is %s\n",typeid(i).name());
printf("typeid of i is %s\n",typeid(f).name());
printf("typeid of i is %s\n",typeid(p).name());
printf("typeid of i is %s\n",typeid(bob).name());
printf("typeid of i is %s\n",typeid(dob).name());

typeid(i)== typeid(j)? printf("i==j.\n" ):printf("no idea.\n" );


typeid(i)== typeid(f)? printf("i==j.\n" ):printf("no idea.\n" );
typeid(p)== typeid(f)? printf("i==j.\n" ):printf("no idea.\n" );
typeid(bob)== typeid(dob)? printf("dob==bob.\n" ):printf("no idea.\n"
);
}
typeid …

class Base{
public:
virtual void A(){};
};

class Derived: public Base


{
public:
void A(){}
};
class Derived1: public Base
{
public:
void A(){}
};
typeid …

int main()
{
Base *bp,b;
Derived d;
Derived d1;

bp=&b;
printf("bp is now with %s\n",typeid(*bp). name());

bp=&d;
printf("bp is now with %s\n",typeid(*bp). name());

bp=&d1;
printf("bp is now with %s\n",typeid(*bp). name());

}
Cast operators

There are four casting operators in C++ with their main usage:

Type caster keyword and Description

static_cast
To convert non polymorphic types.

const_cast
To add or remove the const-ness or volatile-ness type.

dynamic_cast
To convert polymorphic types.

reinterpret_cast
For type conversion of unrelated types.
Using Cast operators

•The syntax is same for the four type cast except the cast name:

name_cast<new_type> (expression)

where:

name either one of the static, const, dynamic or


reinterpret

new_type the result type of the cast.

expression expression to be cast.


Static cast: Example

int main()
{

int sum = 1000;


int count = 21;

double average1 = sum/count;


cout<<"Before conversion = "<<average1<<endl;

double average2 = static_cast<double>(sum)/count;

cout<<"After conversion = "<<average2<<endl;


return 0;
}
Static cast: Example

//enum data type


enum color {blue, yellow, red, green, magenta};

int main()
{
int p1 = 3;
cout<<"integer type, p1 = "<<p1<<endl;
cout<<"color c1 = static_cast<color> (p1)"<<endl;
color c1 = static_cast<color> (p1);
cout<<"enum type, c1 = "<<c1<<endl;

return 0;
}
Constant cast: Example
int main()
{
const int p = 20;

cout<<"const p = "<<p<<"\nq = p + 20 = "<<(p + 20)<<endl;

//The following code should generate error, because


//we try to modify the constant value...
//uncomment, recompile and re run, notice the error...
//p = 15;
//p++;

//remove the const...


int r = const_cast<int&> (p);
//the value of 10 should be modified now...
--r;
cout<<"Removing the const, decrement by 1,”;
cout<<“\n New value = "<<r<<endl;
return 0;
}
Constant cast: Example
struct One
{
//test function...
void funct1()
{ cout<<"Testing..."<<endl;}
};

//const argument, cannot be modified...


void funct2(const One& c)
{
//remove the const...
One &noconst = const_cast<One&> (c);
cout<<"The reference = "<<&noconst<<endl;
noconst.funct1();

//c.funct1(); //uncomment the above and notice it


}
Constant cast: Example

int main()
{
One b;
funct2(b);
return 0;
}
Dynamic cast: Example

class Base1 {};

//derived class...
class Derived1:public Base1 {};

//another derived class


class Derived2:public Derived1{};

//dynamic_cast test function...


void funct1()
{
//instantiate an object…
Derived2* Test1 = new Derived2;

//upcasting, from derived class to base class,


//Derived1 is a direct from Base1
//making Test2 pointing to Derived1 sub-object of Test1

Derived1* Test2 = dynamic_cast<Derived1*>(Test1);

cout<<"Derived1* Test2 = dynamic_cast<Derived1*>(Test1);"<<endl;


Dynamic cast: Example

if(!Test2)
cout<<"The conversion is fail..."<<endl;
else
cout<<"The conversion is successful..."<<endl;

//upcasting, from derived class to base class


//Derived2 is an indirect from Base1

Base1* Test3 = dynamic_cast<Derived1*>(Test1);

cout<<"\nBase1* Test3 = dynamic_cast<Derived1*>(Test1);"<<endl;


if(!Test3)
cout<<"The conversion is fail..."<<endl;
else
cout<<"The conversion is successful..."<<endl;
}
int main()
{
funct1(); return 0;
}
Standard Templates Library in C++
Introduction: STL

•The Standard Template Library, or STL, is a C++ library of


container classes, algorithms, and iterators;

•It provides many of the basic algorithms and data structures of


computer science.

•The STL is a generic library, meaning that its components are


heavily parameterized:

•Almost every component in the STL is a template.

•You should make sure that you understand how templates


work in C++ as we have done before you use the STL.
A brief Introduction to STL

•Containers and algorithms

•Like many class libraries, the STL includes container classes:

•Classes whose purpose is to contain other objects.

•The STL includes the classes vector, list, deque, set, multiset,
map, multimap, hash_set, hash_multiset, hash_map, and
hash_multimap.

•Each of these classes is a template, and can be instantiated to


contain any type of object.

•You can, for example, use a vector<int> in much the same way as you
would use an ordinary C array, except that vector eliminates the job of
managing dynamic memory allocation by hand.

Das könnte Ihnen auch gefallen