Sie sind auf Seite 1von 68

C++

Shem Chandran

Structures
Collections of data records Role expanded in C++; like a class except for the default access A struct is defined by: struct myStructType /*: inheritances */ { // public members protected: // protected members private: // private members } myStructName; //optional list of variables object of type myStructType myStructType obj1;

Structures
// struct definition: struct Point { double x, y; }; // create variables int main() { Point blank; blank.x = 3.0; blank.y = 4.0; int x = blank.x; } // assignment operator Point blank = { 3.0, 4.0 }; Point blank; blank = {3.0, 4.0} ;//WRONG Point p1 = { 3.0, 4.0 }; Point p2 = p1;

Structures
//Structures as return types Point findCenter (Rectangle& box) { double x = box.corner.x + box.width/2; double y = box.corner.y + box.height/2; Point result = {x, y}; return result; } int main() { Rectangle box = { {0.0, 0.0}, 100, 200 }; Point center = findCenter (box); printPoint (center); Return 0; } Rectangle (Point corner, int width, int height);

Unions
Similar to structs the fields of a union share the same memory location multiple ways of viewing the same; No inheritance union item { // The item is 16-bits short theitem; struct { char lo; char hi; } portions; //struct type has no name // in little-endian lo accesses low 8-bits, hi upper 8-bits }; int main() { item myitem; myitem.theItem = 0xBEAD; myitem.portions.lo = 0xEF; // The item is now 0xBEEF return 0; }

Classes
Classes are user defined types have both data and functions members - encapsulation An instance of a class is called an object Class is a logical abstraction, objects exist in memory class myClass { data /* variables, constants */ functions access-specifier /* public, protected and private */ data functions /* section access-specifier, data, functions can be repeated */ } object-list; /* optional object list */ Data and functions are known as members of the class An object of class is declared by: myClass Ob;

Classes
Access-specifier private (default specifier) only members of the class and friends can access protected like private, but can be accessed also by derived classes private allows the members to be accessed by other parts of the program Member variables (also known as instance variables) Non-static members cannot be initialized in the class No member can be declared as auto, extern or register Member variables are usually private for encapsulation; made public if heavily used for faster runtime

Classes
class employee { char name[80]; double wage; public: void putname(char *n); void getname(char *n); void putwage(double w); double getwage(); }; void employee:: p putname(char *n) { strcpy(name, n); } void employee::getname(char *n) { strcpy(n, name); } void employee::putwage(double w) { wage = w; } double employee::getwage() { return wage; }

Classes
i int main() { employee ted; char name[80]; ted.putname("Ted Jones"); ted.putwage(75000); ted.getname(name); cout << name << " makes $"; cout << ted.getwage() << " per year. << endl; return 0; }

Friend Functions
A non-member function can be granted access to the private & protected members of a class by defining as a friend function. The prototype of the friend function must be declared in the class preceded by friend A function can be friend of >1 class, and be member of another class /* sum() is not a member class myclass { function of any class */ int a, b; i int sum(myclass x) public: { void set_ab(int i, int j); /* sum(), a friend of myclass, can directly friend int sum(myclass x); }; access a and b. */ void myclass::set_ab(int i, int j) { return x.a + x.b; a = i; } b = j; }

A class can be declared to be a friend class of another class The friend class & all its member functions have access to the private & protected members defined in the other class class TwoValues { int Min::min(TwoValues x) { int a; return x.a < x.b ? x.a : x.b; int b; } public: TwoValues(int i, int j) { int main() { a = i; b = j; } TwoValues ob(10, 20); friend class Min; Min m; }; cout << m.min(ob); class Min { return 0; public: } int min(TwoValues x); };

Friend Classes

Inline Functions
Short functions, not actually called but expanded in line at each invocation (like a function macro); request to compiler; its definition is preceded by inline keyword inline int max(int a, int b) { return a>b ? a : b; } int main() { cout << max(10,20); return 0; } Efficient code, reduce overheads in function call, return Short functions defined inside the class declaration including constructors/destructors are made inline automatically class myclass { int a, b; public: void init (int I, int j) { a=i; b=j } }

Special member functions (same name as class) called when new instances of a class are created Can define the data members upon object instantiation by passing parameters default constructor if none defined class myclass { int main() { int a, b; myclass ob(3, 5); public: ob.show(); myclass(int i, int j) {a=i; b=j;} return 0; } void show() {cout << a << " " << b; } //alternate way }; myclass ob = myclass (3, 4); //constructor with one parameter i int main() class X { { int a; X ob = 99; public: return 0; } X (int j) { a = j:} }

Constructors

Static Data Members


When static precedes a data members declaration, only one copy of that variable exists, and all objects derived from the class will share that variable A global definition of the static variable must be done outside the class for storage allocation i int main() class shared { { static int a; shared x, y; int b; public: void set(int i, int j) {a=i; b=j;} void show(); }; int shared::a; // define a void shared::show() { cout << a << << b; } x.set(1, 1); // set a to 1 x.show(); //1 1 y.set(2, 2); // change a to 2 y.show(); //2 2 x.show(); //2 1 }

Static Data Members


A static member variable exists before any object of the class is created In example below, a is static & public; hence can be accessed in main before any class object is created class shared { public: static int a; }; int shared::a; // define a // initialized in main before creating any objects // referred to by class name & scope operator int main() { shared::a = 99; cout << "initial value of a: " << shared::a << "\n"; shared x; cout << "This is x.a: " << x.a; return 0; }

Static Data Members


Static members can be used as for access control of some resource between objects & as counters of objects class Counter { int main(void) public: { static int count; Counter o1; Counter() { count++; } cout << Counter::count << "\n"; ~Counter() { count--; } Counter o2; }; cout << Counter::count << "\n"; int Counter::count; f(); void f() { cout << Counter::count << "\n"; Counter temp; return 0; } cout << Counter::count << "\n"; } //eliminate global variables //temp destroyed when f returns

Static Member Functions


Member functions may also be declared static Like static member variables, static member functions are not attached to an object; they can be called directly using class name & scope operator; they can also be called through objects of the class They do not have a this operator, since they need not have an object They may not be virtual or declared const or volatile They can access only static member variables; they cannot access non-static member variables (which must b belong to a class object) static member functions have limited applications; they can be used to pre-initialize private static data before any object is actually created

Static Member Functions


Example using static member function to generate IDs class IDGenerator { private: static int NextID; public: static int GetNxtID() {return NextID++;} 1 }; 2 int IDGenerator::NextID=1; 3 int main() { for (int i=0; i<3; i++) cout << IDGenerator::GetNxtID() << endl; return 0; }

Misc Class topics


Constructors executed in creation order & destructors in reverse order Nested class One class (nested class) defined inside another The nested class is valid only within the scope of enclosing class, a container class Local classes A class can be defined within a function All member functions must be defined within the class declaration The local class cannot access local variables of the function, except for static local variables or extern variables declared within the function No static variables may be declared inside a local class

Array Objects
Arrays of objects class cl int i; public: cl(int j) { i=j;} //constructor needs only 1 argument }; int main() { cl ob[3] = {1, 2, 3}; //short for {cl(1), cl(2), cl(3)}; cl a[5]; //error needs constructor with no parameter initializers //Adding another constructor in class declaration cl() {i=0;} //for non-initialized arrays cl b[5]; //not an error }

Pointers to Objects
To access class members using a pointer to an object use -> class cl { i int main() int i; { public: cl ob[3] = {1, 2, 3}; cl(int j) { i=j; } cl *p; int get_i() { return i; } int i; }; p = &ob.i; //addr of ob.i int main() { p = ob; // get start of array cl ob, *p; for(i=0; i<3; i++) { p = &ob; // get address of ob cout << p->get_i() << "\n"; cout << p->get_i(); //note -> p++; // point to next object return 0; } } return 0; }

this Pointer
When a member function is called, c++ adds a hidden pointer this to the invoking object class employee { double wage; public: void putwage(double w) { wage = w;} }; i int main() { employee ted; ted.putwage(75000); } The function call has only one parameter ted.putwage(75000); c++ internally converts it to p putwage(&ted, 75000) and converts the function to void putwage (employee* const this, double w) { this->wage = w; }

Pointers to Derived Types


In general a pointer of one type cannot point to an object of a different type A pointer to a base class can point to an object of a class d derived from that base class (opposite is not true) But it can access only members of the base class and not members of the derived class in that object If the base pointer is cast into a derived pointer, it can gain full access to the derived class Since pointer arithmetic is relative to the base type, arithmetic of the pointer to derived type can cause errors

Pointer to Derived Type int main() {


base *bp; derived d; bp = &d; // base ptr points to derived bp->set_i(10); cout << bp->get_i(); bp->set_j(88); // error cout << bp->get_j(); // error class derived: public base { // access now allowed because int j; of cast public: ((derived *)bp)->set_j(88); void set_j(int num) { j=num; } cout << ((derived *)bp)->get_j(); int get_j() { return j; } return 0; }; } class base { int i; public: void set_i(int num) { i=num; } int get_i() { return i; } };

References
You can declare a reference that is simply address of a variable It must be initialized when created; the object pointed to cannot be changed later This independent reference is another name for the object

i int main() int b = 19; { ref = b; int a; cout << a << " "<< ref<<endl; int &ref = a; // independent ref ref--; // this decrements a // not affect what ref refers to a = 10; cout << a << " "<< ref<<endl; cout << a << " "<< ref <<endl; return 0; ref = 100; } cout << a << " "<< ref <<endl;

Pointers and references


When declaring pointer and reference variables, some programmers associate the * and the & with the type name rather than the variables int& p; // & associated with type int &p; // & associated with variable According to the formal c++ syntax, the * and & are not distributive over a list of variables int* a, b; // b is an integer, while a is a pointer to an integer. The visual confusion can mislead int *a, b; // A preferred way

const objects
Declaration of objects as mutable or immutable Simple data type int const k = 7; or const int k = 7; value given at creation Pointers and references pointer to a const or const pointer int const *ptr or const int *ptr //pointee not modifiable int *constant ptr //pointer is constant, not reassignable int const *const ptr //both pointee & pointer are constant int const &num =7; //num can be set only at creation int &const num //error, const is redundant Objects const employee Ted; or employee const Ted;

Member functions if tagged const, cannot modify the object's data members int get() const { return j: } Const member functions can be called by const and nonconst objects, but non-const member functions cannot be invoked by const objects Often both const and non-const versions of functions w will be available (different implicit this parameter) Parameters to functions can also be made const void f(employee &Ted, const employee &Bob); const_cast, casts away the const nature of an object, making it modifiable for compatibility with an old library

const functions

Member pointers and references are shallow wrt to the const object, so while the member pointers cannot be modified, the pointees can be modified class S { int val; int *ptr; } void f(const S &s1) { int i = 42; s1.val = i; //error: s1 is const, so val is a const s1.ptr = &i; //error: s1 is const, so ptr is a const pointer *s1.ptr = i; //ok; data pointed to by ptr is mutable Volatile the value may not be modified by program, but may be changed by h/w; hence all references must be r read everytime (no temp storage or optimization)

const functions

Memory Allocation
3 Kinds of Program Data Static Data: Allocated at compiler time Dynamic Data: explicitly allocated and deallocated during program execution by C++ instructions written by programmer using operators new and delete Automatic Data: automatically created at function entry, resides in activation frame of the function, and is destroyed when returning from function

Memory Allocation
Dynamic Memory Allocation Static memory - where global and static variables live Heap memory dynamically allocated at execution time "managed" memory accessed using pointers Stack memory - used by automatic variables
Static Memory Global Variables Static Variables Heap Memory Free storage Dynamically allocated Stack Memory Auto variables Function parameters

In C, functions such as malloc () are used to dynamically allocate memory from the Heap. In C++, this is accomplished using the new and delete operators new is used to allocate memory during execution time returns a pointer to the address where the object is to be stored always returns a pointer to the type that follows the new

Dynamic Memory Allocation


H ig h - e n d S t a c k Run-time allocated memory

H s t a P

a t i c

p d a

Compile-time allocated memory t a m

r o g r a c o d e

- e

new DataType char* ptr; ptr = new char; {new allocates the requested object of type requested & returns a pointer to (address of ) the memory allocated} *ptr = B; { Note: The dynamic data has no variable name} cout << *ptr; The dynamically allocated object exists until the delete operator destroys it

new and delete operators

The NULL Pointer There is a pointer constant called the null pointer d denoted by NULL (not memory address zero) It is an error to dereference a pointer whose value is N NULL (causes crash) while (ptr != NULL) { } Operator delete delete ptr or delete [ ] ptr {for arrays} The object or array currently pointed to by ptr is deallocated & the memory is returned to the free store ptr itself is not deallocated; its value is undefined; good to make it NULL

new and delete operators

Passing Objects by Value


When an object of a class is passed by value to a function, a copy of the object is made and this becomes the parameter in the function The objects copy constructor is called and not the normal class constructor (which may initialize). If an explicit copy constructor is not defined, c++ provides a default constructor, which is a bitwise (identical) copy When the function terminates, the copy of the object used as a parameter, is destroyed and the destructor is called This can sometimes cause problems if the destructor frees memory, which is the same as that of the original object Hence a copy constructor of the class must be defined

Passing Objects by Value


class myclass { int i; public: myclass(int n); ~myclass(); void set(int n) { i=n; } int get() { return i; } }; myclass::myclass(int n) { i = n; cout << "Construct " << i; } myclass::~myclass() { cout << "Destroy " << i; } void f(myclass ob) { ob.set(2); cout<<Local i: "<< ob.get(); } int main() { myclass o(1); f(o); cout << Main i: "; cout << o.get_i() << "\n"; return 0; } Construct 1 Local i: 2 Destroy 2 Main i: 1 Destroy 1

Reference Parameters
Two ways to pass parameters by reference: // c type pointers to arguments void neg(int *i) { *i = -*i; } int main() { int x; x = 10; cout << x << " negated is "; neg(&x); cout << x << "\n"; return 0; } //reference parameters void neg(int &i) { i = -i; // reference, not need * } int main() { int x; x = 10; cout << x << " negated is "; neg(x); // not need & cout << x << "\n"; return 0; }

When an object is passed by reference, a copy of the object is not made; hence constructor is not called When the function terminates, destructor is not called Faster, as stack operations saved class cl { int main() { int id; cl o(1); public: o.i = 10; int i; o.neg(o); cl::cl(int num) { cout << o.i << "\n"; cout << "Construct "<<num<<endl; return 0; id = num; } } cl::~cl() { cout << "Destroy " << id << endl; } Construct 1 void neg(cl &o) { o.i = -o.i; } //dot op -10 Destroy 1 };

Passing Objects by Reference

Dynamic Memory Allocation


c++ provides two dynamic allocation operators: new, delete cs malloc(), free() are supported but best not to mix both new is followed by a type specifier (and an optional initializer), and a pointer to the allocated location is returned int *p; p = new int (87); //allocates an int with value 87 To allocate an array size is specified; pointer to first element is returned; arrays cannot be initialized at allocation int *q; q = new int [10]; //q points to first element q[0] Memory created by new is allocated in the heap and hence must be deleted explicitly delete p; delete [] q; c++ provides 2 methods to detect allocation failure: throwing an exception bad_alloc by returning null pointer (nothrow method) b

Dynamic Memory Allocation


i int main() { int *p; try { p = new int; // allocate space for an int } catch (bad_alloc xa) { cout << "Allocation fail\n"; return 1; } *p = 100; delete p; #include <iostream> #include <new> using namespace std; i int main() { int *p, i; //use nothrow option p = new(nothrow) int[32]; if(!p) { cout << "Allocation fail\n"; return 1; } for(i=0; i<32; i++) p[i] = i; delete [] p; // free the memory

Allocating Objects
When a class object is allocated dynamically by new, the object is created, calling a constructor and a pointer returned; when it is freed, its destructor is called class balance { r = new balance [2]; double cur_bal; //error - no parameterless constructor public: balance(double n) {cur_bal = n; } // provide since no default void set(double n) { cur_bal = n;} balance() {cur_bal = 0;} // in the class declaration } //then initialize int main() { r[0].set {12000.0}; balance *p, *q; r[1].set {11000.0}; p = new balance; delete p, q, r[]; p->set(12500.0); return 0; } q = new balance (15000.0);

Function Overloading
Same name for 2 or more functions Each definition should differ in the list of parameters (number and/or types). Just different return type will not suffice Sometimes, though they appear different, are the same void f(int *p); void f(int p[]); // error, *p is same as p[], both are pointers Constructers are often overloaded for flexible initialization class date { int day, month, year; public: date(); date(int m, int d, int y); date(char *d); //to allow 03/15/2010 or mar 15 2010

Default Copy Constructor


If a copy constructor is not defined, c++ provides a default copy constructor, which does a bitwise copy of the reference object. This can have problems if the object has pointers class loc { int long, int lat; loc (int i, int j) { lon = i; lat = j} } int main() { loc A(3, 5); loc B(A);
A B 3 5 3 5

class loc { int n, int *d; } int main() { loc A; loc B(A);
A B 2 d 2 d

heap 5 7

Copy Constructor
C++ allows you to define a (deep) copy constructor, which will be used when one object is used to initialize another class array { int main() { int *p; array A(5); int size; int i; public: array(int sz) {size = sz; for (i=0; i<5; i++) A.put(i,i); p = new int[sz]; } //create array B initialized by A put (int i, int j) { p[i] = j; } array B(A); ~array() { delete [] p; } array::array(const array &a) { delete A, B; int i; return 0; } p = new int[sz]; for(i=0; i<a.size; i++) p[i] = a.p[i]; }

Default Function Arguments


c++ allows a function to assign a parameter value when no argument for that parameter is specified in the call // A custom version of strcat() int main() { char str1[80] = "This is a test"; void mystrcat (char *s1, char str2[80] ="0123456789"; char *s2, int len=-1) { mystrcat(str1, str2, 5); // find end of s1 //concatenate 5 chars while(*s1) s1++; if(len == -1) len = strlen(s2); cout << str1 << '\n'; strcpy(str1, "This is a test"); while(*s2 && len) { mystrcat(str1, str2); *s1 = *s2; // copy chars //concatenate entire string s1++; s2++; len--; cout << str1 << '\n'; } return 0; *s1 = '\0'; // null terminate s1 } } //alternate to function overloading

Operators can be overloaded to perform special operations relative to the classes; the original operator functions are retained relative to previous operands Operators are overloaded by creating operator functions as either member functions or friend functions // Overload + for loc class loc { loc loc::operator+(loc op2) { int long, lat; loc temp; public: temp.long = op2.long + long; loc() {} temp.lat = op2.lat + lat; loc(int lg, int lt) { return temp; } long = lg; lat = lt; } void show() { cout << long << Int main() { << lat << endl; } loc ob1(10,20), ob2(15,50); loc operator+(loc op2); ob1 = ob1 + ob2; }; ob1.show(); return 0; }

Operator Overloading

Operator loc +() has only one parameter though it overloads the binary + operator. The operand on the left side is implicitly passed through this The overloaded operator commonly returns an object of the class it operates on. It does not modify the operands // Overload asignment for loc // Overload prefix ++ for loc loc loc::operator=(loc op2) loc loc::operator++() { long = op2.long; { lat = op2.lat; long++; return *this; //return object lat++; generating the call return *this; } } loc ob1(1,2), ob2(3,4), ob3(5,6); ob1 = ob2 = ob3;

Operator Overloading

Operator Overloading
The postfix operator is defined as loc operator++(int x) //where x=0 The shorthand operators +=, -= can also be overloaded loc loc::operator+=(loc op2) { long += op2.long; lat += op2.lat; return *this; }

Operator Overloading using a Friend function


An operator can be overloaded by a nonmember function, which is usually a friend function Since the friend function does not have this pointer, its operands are passed explicitly When overloading a binary operator using a friend, the left operand is passed as first parameter

Operator Overloading using a Friend function


class loc { loc operator+(loc op1, loc op2) { int long, lat; loc temp; public: temp.long = op1.long + loc() {} // need to constr temp op2.long; loc(int lg, int lt) { temp.lat = op1.lat + op2.lat; long = lg; lat = lt; } return temp; void show() { } cout << long << << lat; } int main() { friend loc operator+(loc op1, loc ob1(10, 20), ob2( 5, 30); loc op2); ob1 = ob1 + ob2; }; ob1.show(); return 0; }

Inheritance
Allows creation of hierarchical classifications A Base Class (Parent or Super Class) is the class whose members are inherited by a Derived Class (Child or Class) class derivedclass-name : access-specifier baseclass-name The access-specifier is public, protected or private If not specified the access is by default private for classes and public for structs In all inheritance access cases, the private members of a base class not accessible from the derived classes Inheritance is a mechanism for building class types from existing class types, defining new class types to be A specialization An augmentation of existing types

Simple Inheritance
class point { protected: int x, y; public: point (int a, int b) { x=a; y=b; } void set(int a, int b) { x=a; y=b; } void show() { cout << x << " " << y << "\n"; } }; class point3d : public point { int z; public: point3d (int a, int b, int c) : point (a, b) { z=c; } void show() { cout << x << " " << y << " " << z << "\n"; } };

Access specifier in the derived class


The access specifier of a member in the derived class depends on the original access specifier of the member and the inheritance specifier
Access specifier in base class

private member is inaccessible member is inaccessible member is inaccessible

protected member is private member is protected member is protected

public member is private member is protected member is public

private Inheritance specifier

protected

public

Multiple Inheritance
class base1 { protected: int x; public: void showx() { cout << x << endl; } }; class base2 { protected: int y; public: void showy() { cout << y << endl; } }; class derived: public base1, public base2 { public: void set(int i, int j) { x=i; y=j; } }; int main() { derived ob; ob.set(10, 20); // derived constr ob.showx(); // from base1 ob.showy(); // from base2 return 0; } //assignment redo using only one routine called show in all 3 classes

Constructors & Destructors in Inheritance


class base { public: base() { cout << "Const base\n"; } ~base() { cout << "Dest base\n"; } }; class derived: public base { public: derived() { cout << "Const derived\n"; } ~derived() { cout << "Dest derived\n"; } }; int main() { derived ob; return 0; }
class base { public: base() { cout << "Const base; } ~base() { cout << "Destbase";}}; class drvd1 : public base { public: drvd1() { cout <<"Constdrvd1"; } ~drvd1() {cout<<"Destdrvd1";} }; class drvd2: public drvd1 { public: drvd2() { cout <<"Constdrvd2"; } ~drvd2(){cout<<"Destrdrvd2";}}; int main() { drvd2 ob; return 0; }

Passing Parameters to Base-Class Constructors


class base { protected: int i; public: base(int x) { i=x; cout<<"Cons base; } ~base() { cout << "Dest base\n"; } }; class derived: public base { int j; public: // drvd uses x; y is passed to base derived(int x, int y): base(y) { j=x; cout << "Cons derived\n"; } ~derived() { cout << "Dest derived\n"; } void show() { cout << i <<" "<<j; } };

Passing Parameters to Base-Class Constructors


class base1 { protected: int i; public: base1(int x) {i=x;cout<<"Cnsbas1";} ~base1() {cout<<"Dstbas1; } }; class base2 { protected: int k; public: base2(int x) {k=x;cout<<"Cnsbas2"; } ~base2(){cout<<"Dstbase1"; } } class derived: public base1, public base2 { int j; public: drvd(int x, int y, int z): base1(y), base2(z) { j=x; cout << "Cnsdrvd; } ~drvd() {cout<<"Dstdrvd";} void show() { cout << i << " " << j << " " << k; } };

Virtual Base Classes


Ambiguity can be introduced when multiple base classes are inherited class derived3 : public class base { derived1, public derived2 { public: public: int i; int sum; }; }; class derived1 : public base { int main() { public: derived3 ob; int j; ob.i = 10; // ambiguous i??? }; ob.j = 20; class derived2 : public base { ob.k = 30; public: ob.sum = ob.i + ob.j + ob.k; int k; cout <<ob.i<<ob.j<<ob.k; }; return 0; }

Virtual Base Classes


Two ways to remedy: scope, virtual int main() { /*derived3 inherits derived1 & derived2. But only 1 copy derived3 ob; of base class*/ ob.derived1::i = 10; .. // drvd1 inherits base as virtual class derived3 : public derived1, public derived2 { class derived1 : virtual public public: base { int sum; }; public: int main() { int j; }; derived3 ob; // drvd2 inherits base as virtual ob.i = 10; // unambiguous class derived2 : virtual public //note: base is real in derived base { derived1 myclass; public: myclass.i = 10; int k; };

Virtual Functions
A virtual function is a member function declared within a base class and redefined by a derived class The virtual function in the base class defines the form of the interface to that function. Each redefinition by a derived class creates a specific method related to that class Accessed normally virtual functions behave like other member functions When accessed via a pointer, they support run-time polymorphism (one interface, multiple methods) When a base pointer (or base-class reference) points to a derived object, c++ determines which version of the function to call, based on the type of object This determination is made at run-time

Virtual Functions class base { int main() { public: base *p, b; virtual void vfunc() { derived1 d1; cout << "This is base's vfunc()"; } derived2 d2; }; p = &b; // point to base class derived1 : public base { p->vfunc(); // base's vfunc() public: p = &d1; // point to derived1 void vfunc() { cout<<"This is derived1's vfunc(); } p->vfunc(); /* derived1's vfunc() */ }; p = &d2; // point to derived2 class derived2 : public base { p->vfunc(); /* derived2's public: vfunc() */ void vfunc() { cout<<"This is derived2's vfunc(); } return 0; } Note: }; d2.vfunc(); //calls derived2s Note: Virtual function not same as vfunc() overloaded function

Calling Virtual Functions thro base class ref


/* Use a base class reference class base { parameter */ public: void f(base &r) { virtual void vfunc() { r.vfunc(); cout << "This is base's vfunc()"; } } }; class derived1 : public base { int main() { public: base b; void vfunc() { derived1 d1; cout<<"This is derived1's vfunc(); } derived2 d2; }; f(b); // pass base object to f() class derived2 : public base { f(d1); // pass derived1 obj to f public: f(d2); // pass derived2 obj to f void vfunc() { return 0; } cout<<"This is derived2's vfunc(); } };

Virtual Functions
When a virtual function is inherited, its virtual nature is also inherited A derived class that has inherited a virtual function is itself used as a base class for another derived class, which can again override the virtual function A derived class does not have to override a virtual function. In this case, when an object of this derived class accesses that function, the function defined by the base class is used Like inheritance, virtual functions are also hierarchical When a derived class fails to override a virtual function, the first redefinition found in reverse order of derivation is used C++ constructs a Virtual Function Table (VFT or Vtable) for each class that has a virtual function; each virtual function has entry to the most derived function in the inheritance hierarchy

Pure Virtual Functions and Abstract Classes


A pure virtual function is a virtual function that has no definition within the base class virtual type func-name(parameter-list) = 0; When a virtual function is pure, any derived class must provide its own definition A class that contains at least one pure virtual function is said to be abstract No objects of an abstract class may be created However, pointers and references to an abstract class can be created to support run-time polymorphism, which relies on base-class pointers and references to select the proper virtual function

Using Virtual Functions


class convert { protected: double val1; // initial value double val2; //converted value public: convert(double i) { val1 = i; } double getconv() { return val2; } double getinit() { return val1; } virtual void compute() = 0; };
// Liters to gallons. class l_to_g : public convert { public: l_to_g(double i) : convert(i) { } void compute() { val2 = val1 / 3.7854; } }; // Fahrenheit to Celsius class f_to_c : public convert { public: f_to_c(double i) : convert(i) { } void compute() { val2 = (val1-32) / 1.8; } };

Using Virtual Functions


int main() { convert *p; // pointer to base class l_to_g lgob(4); f_to_c fcob(70); // use virtual function to convert p = &lgob; cout << p->getinit() << " liters is "; p->compute(); cout << p->getconv() << " gallons\n"; // l_to_g p = &fcob; cout << p->getinit() << " in Fahrenheit is "; p->compute(); cout << p->getconv() << " Celsius\n"; // f_to_c return 0; } // Feet to meters class f_to_m : public convert { public: f_to_m(double i) : convert(i) { } void compute() { val2 = val1 / 3.28; } };

An important use of abstract classes and virtual functions is in class libraries. You can create and control the interface of a general class, letting programmers adapt to their needs

Polymorphism
Key principle: one interface, multiple methods Compile-time polymorphism is achieved by overloading functions and operators Early binding (efficient) Run-time polymorphism is accomplished by inheritance and virtual functions Late binding When access is via a base pointer or reference, the virtual function actually called is determined by the type of object pointed to by the pointer In most cases this cannot be determined at compile time and the object and the function are not linked till run-time The main advantage of late-binding is flexibility, allowing you to create programs that can respond to events occurring as it executes Late binding can cause slower execution times

Complex objects are built from smaller simpler objects To facilitate building complex classes from simpler classes, c++ allows us to use classes as member variables in other classes #include CPU.h #include Mboard.h #include RAM.h Class PC { CPU m_cCPU Mboard m_cMboard RAM m_cRAM }; PC::PC(int nCPUspeed, char *sMbrdModel, int nRAMsize) : m_cCPU(nCPUspeed), m_cMboard(sMbrdModel), m_cRAM(nRAMsize) { }

Class Composition

Class Composition
class Mouth { public: void eat(Food bite); } //by inheritance ( is-a ) class Person : public Mouth{ }; //by composition ( has-a ) class Person { public: void eat(Food bite) { itsMouth.eat(bite): } private: Mouth itsMouth; }

Das könnte Ihnen auch gefallen