1 / 84

Dynamic object creation

Dynamic object creation. Object creation. When a C++ object is created, two events occur: Storage is allocated for the object. The constructor is called to initialize that storage. Step one can occur in several ways

parker
Télécharger la présentation

Dynamic object creation

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Dynamic object creation

  2. Object creation • When a C++ object is created, two events occur: • Storage is allocated for the object. • The constructor is called to initialize that storage. • Step one can occur in several ways • Storage can be allocated before the program begins, in the static storage area. This storage exists for the life of the program. • Storage can be created on the stack whenever a particular execution point is reached (an opening brace). That storage is released automatically at the complementary execution point (the closing brace). • Storage can be allocated from a pool of memory called the heap (also known as the free store)

  3. Operator new • C++ can combine all the actions necessary to create an object into a single operator called new. • When you create an object with new (using a new-expression), it allocates enough storage on the heap to hold the object and calls the constructor for that storage. MyType *fp = new MyType(1,2); • Here at runtime the equivalent of malloc(sizeof(MyType) i)s called (often, it is literally a call to malloc( )), and the constructor for MyType is called with the resulting address as the this pointer, using (1,2) as the argument list • The default new checks to make sure the memory allocation was successful before passing the address to the constructor. • If the constructor has no arguments, you can write the new-expression without the constructor argument list: MyType *fp = new MyType;

  4. Operator delete • The complement to the new-expression is the delete-expression • it first calls the destructor and then releases the memory (often with a call to free( )). • Just as a new-expression returns a pointer to the object, a delete-expression requires the address of an object. delete fp; • delete can be called only for an object created by new

  5. Memory manager overhead • When you create automatic objects on the stack, the compiler knows the exact type, quantity, and scope. • Creating objects on the heap involves additional overhead, both in time and in space. • You call malloc( ), which requests a block of memory from the pool • The block must be recorded so further calls to malloc( ) won’t use it, and so that when you call free( ), the system knows how much memory to release.

  6. new & delete for arrays • In C++, we can create arrays of objects on the stack or on the heap with equal ease, and the constructor is called for each object in the array. • Ex: MyType* fp = new MyType[100]; • This allocates enough storage on the heap for 100 MyType objects and calls the constructor for each one. • For deleting the array we use the syntax delete []fp; • The empty brackets tell the compiler to generate code that fetches the number of objects in the array and calls the destructor for that many array objects.

  7. Running out of storage • when the operator new cannot find a contiguous block of storage large enough to hold the desired object, a special function called the new-handler is called. • The default behavior for the new-handler is to throw an exception • if you’re using heap allocation in your program, it’s wise to replace the new-handler with a message that says you’ve run out of memory and then aborts the program. • The behavior of the new-handler is tied to operator new • so if you overload operator new the new-handler will not be called by default. • If you want to call the new-handler, you have to write the code to do so inside your overloaded operator new

  8. Example #include <iostream> #include <cstdlib> #include <new> using namespace std; int count = 0; void out_of_memory() { cerr << "memory exhausted after " << count << " allocations!" << endl; exit(1); } int main() { set_new_handler(out_of_memory); while(1) { count++; new int[1000]; // Exhausts memory } }

  9. Overloading new & delete • When we create a new-expression first, storage is allocated using the operator new and then the constructor is called. • In a delete-expression, the destructor is called and then storage is de allocated using the operator delete. • The constructor and destructor calls are never under our control, but we can change the storage allocation functions operator new and operator delete. • C++ allows you to overload new and delete to implement your own storage allocation scheme

  10. Overloading new & delete • The most common reason to change the allocator is efficiency • Another issue is heap fragmentation. • By allocating objects of different sizes it’s possible to break up the heap so that you effectively run out of storage. • When you overload operator new and operator delete, it’s important to remember that you’re changing only the way raw storage is allocated. • The compiler will simply call your new instead of the default version to allocate storage, then call the constructor for that storage.

  11. When you overload operator new, you also replace the behavior when it runs out of memory • so you must decide what to do in your operator new: return zero, write a loop to call the newhandler and retry allocation, or (typically) throw a bad_alloc exception

  12. Overloading global new & delete • when the global versions of new and delete are unsatisfactory for the whole system, you can overload the global versions • That is make the defaults completely inaccessible –you can’t even call them from inside your redefinitions. • The overloaded new must take an argument of size_t (the Standard C standard type for sizes). • This argument is generated and passed to you by the compiler and is the size of the object you’re allocating. • You must return a pointer either to an object of that size or to zero if you can’t find the memory (in which case the constructor is not called!).

  13. #include <cstdio> #include <cstdlib> using namespace std; void* operator new(size_t sz) { printf("operator new: %d Bytes\n", sz); void* m = malloc(sz); if(!m) puts("out of memory"); return m; } void operator delete(void* m) { puts("operator delete"); free(m); } class S { int i[100]; public: S() { puts("S::S()"); } ~S() { puts("S::~S()"); } }; int main() { puts("creating & destroying an int"); int* p = new int(47); delete p; puts("creating & destroying an s"); S* s = new S; delete s; puts("creating & destroying S[3]"); S* sa = new S[3]; delete []sa; } Example

  14. Overloading new & delete for a class • the syntax is the same as overloading any other operator. • When the compiler sees you use new to create an object of your class, it chooses the member operator new over the global version. • However, the global versions of new and delete are used for all other types of objects • You can also overload new & delete operators for arrays

  15. Operator overloading

  16. Operator overloading • The mechanism of giving special meaning to an operator is known as operator overloading • Although the semantics of the operator can be extended, we cannot change its syntax, the grammatical rule like the number of operands, precedence , associativity etc. • When an operator is overloaded its meaning is not lost • We cannot overload • Class member access operators (. , .*) • Scope resolution operator(::) • Size operator (sizeof) • Conditional operator(?:)

  17. Operator overloading • Operator overloading is done with the help of operator function • return type classname:: operator op(op-arglist) { function body//TASK DEFINED } • Operator functions must be either member functions or friend functions • The process of overloading includes the steps • Create the class that defines the data type that is to be used in the overloading operation • Declare the operator function operator op() in the public part of the class. It may be either friend or member function • Define the operator function to implement the required operations

  18. Operator overloading • basic difference between friend function and member function is • member function will not have any argument for unary operators while friend function will have one argument • Member function will have one argument for binary operators while friend function will have two arguments • vector operator +(vector); //vector addition • vector operator – (); // unary minus • friend vector operator +(vector, vector); // vector addition • friend vector operator – (vector); //unary minus

  19. overloading unary minus class space { int x,y,z; public : void getdata(int a, int b, int c); void display(void); void operator – ( ); }; void space::getdata(int a, int b, int c) { x=a; y=b; z=c; } void space :: display(void) {cout<<x<<“ “<<y<<“ “ <<z;} void space::operator-() { x= -x; Y=-y; Z=-z; } int main() { space S; S.getdata(10, -20, 30); cout<<“S : ” ; S.display(); -S; cout<<“S :”; S.display(); Return 0; } operator overloading

  20. Operator overloading • overloaded functions are invoked by expressions such as • op x or x op for unary operators • x op y for binary operators

  21. class complex { float x,y; public: complex(){} complex(float real, float imag) {x=real; y=imag;} complex operator +(complex); void display(); }; complex complex :: operator +(complex c) {complex temp; temp.x = x+c.x; temp.y =y+c.y; return temp; } void complex :: display() { cout<<x<<"+j"<<y; } int main { complex C1,C2,C3; C1 = complex(2.5, 3.5); C2 = complex(1.6 ,2.7); C3 = C1+C2; cout<<"C1=";C1.display(); cout<<"C2=";C2.display(); cout<<"C3=";C3.display(); return 0; } operator overloading- overloading binary operator

  22. Operator overloading • in binary operator overloading, the left –hand operand is used to invoke the operator function and the right hand operand is passed as an argument

  23. class complex { float x,y; public: complex(){} complex(float real, float imag) {x=real; y=imag;} friend complex operator+ (complex, complex); void display(); }; complex operator +(complex a, complex b) {complex temp; temp.x = a.x+b.x; temp.y =a.y+b.y; return temp; } void complex :: display() { cout<<x<<"+j"<<y; } int main { complex C1,C2,C3; C1 = complex(2.5, 3.5); C2 = complex(1.6 ,2.7); C3 = C1+C2; cout<<"C1=";C1.display(); cout<<"C2=";C2.display(); cout<<"C3=";C3.display(); return 0; } Overloading binary operators using friends

  24. Rules for overloading operators • Only existing operators can be overloaded • The overloaded operator must have atleast one operand that is of user defined type • We cannot change the basic meaning of an operator • Overloaded operators follow the syntax rules of the original operators • There are some operators that cannot be overloaded • We cannot use friend functions to overload certain operators • When using binary operators overloaded through a member function, the left hand operand must be an object of the relevant class

  25. Where a friend cannot be used • = assignment operator • () function call operator • [] subscripting operator • -> class member access operator

  26. Manipulation of strings using operators • Strings can be defined as class objects which can be then manipulated like the built-in types • Since the strings vary greatly in size, we use new to allocate memory for each string and a pointer variable to point to the string array • A typical string class will look like this Class string { Char *p; Int len; Public: //member functions to initialize //and manipulate strings };

  27. Mathematical operations on strings #include<iostream.h>’ #include<string.h> Class string { Char *p; Int len; Public: String(){len=0;p=0;} String(const char * s); String(const string & s);// copy constructor ~string(){delete p;} //+ operator friend int operator+(const string &s, const string &t); //<= operator friend int operator<=(const string &s, const string &t); Friend void show(const string s); };

  28. String :: string(const char *s) { Len=strlen(s); P=new char[len+1]; Strcpy(p,s); } String :: string(const string & s) { Len=s.len; P=new char[len+1]; Strcpy(p,s.p); } String operator+(const string &s,const string &t) { String temp; Temp.len=s.len+t.len; Temp.p=new char[temp.len+1]; Strcpy(temp.p,s.p); Strcat(temp.p,t.p); Return(temp); }

  29. Int operator<=(const string &s, const string &t) { Int m=strlen(s.p); Int n=strlen(t.p); If(m<=n) return(1); Else return(0); } Void show(const string s) { Cout<<s.p; }

  30. Int main() { String s1=“new”; String s2=“york” String s3=“delhi”; string t1=s1; string t2=s2; string t3=s1+s3; Show(t1); Show(t2); Show(t3); If(t1<=t3) { Show(t1); Cout<<“smaller than”; Show(t3); } Else { Show(t3); Cout<<“smaller than”; Show(t1); } Return 0; }

  31. Type conversions • Consider the following statement v3=v1+v2;// v1 & v2 are objects of different classes • For built in types the compiler will do type conversions • But for user defined types, we must design the conversion routines • Three types of situations might arise in the data conversion between uncompatible types • Conversion from basic type to class type • Conversion from class type to basic type • Conversion from one class type to another class type

  32. Basic to class type • Here we can use constructors to perform a type conversion from argument’s type to constructor’s class type String :: string(const char *s) { Len=strlen(s); P=new char[len+1]; Strcpy(p,s); } • The constructor builds a string type object from a char* type variable a

  33. Example: string s1, s2; Char* name1=“ibm pc”; Char* name2=“apple”; S1=string(name1); S2=name2; • The constructors used for the type conversion take a single argument whose type is to be converted

  34. Class to basic type • C++ allows us to define an overloaded casting operator that could be used to convert a class type data to a basic type • The general form of an overloaded casting operator function usually referred to as conversion function, is: Operator typename() { //(function statements) } • This function converts a class type to typename

  35. Ex: vector :: operator double() { Double sum=0; For(int i=0;i<size;i++) sum=sum+v[i]*u[i]; Return sqrt(sum); } • the operator double() can be used as follows: Double length=double(v1); or Double length=v1; Where v1 is an object of type vector • The casting operator function should satisfy the following conditions • It must be a class member • It must not specify any return type • It must not have any arguments

  36. One class to another class type • Example : Objx=objy; //object of different types • Objx belongs to class x • Objy belongs to class y • Y->source class • X->destination class • The conversion can be carried out by either a constructor or a conversion function • It depends upon whether the type conversion function to be located in the source class or destination class

  37. Ex1: //inside class invent1 Operator invent2() { Invent2 temp; Temp.code=code; Temp.value=price*items; Return temp; } Ex2: //inside invent2 Invent2(invent1 p) { Code=p.getcode(); Value=p.getitems()*p.getprice; } It can be invoked by d1=s1; or d1=invet2(s1);

  38. References & Copy-Constructor

  39. Pointers in C++ • The most important difference between pointers in C and those in C++ is that C++ is a more strongly typed language. • C doesn’t let you casually assign a pointer of one type to another, but it does allow you to accomplish this through a void*. Thus, bird* b; rock* r; void* v; v = r; b = v; • This feature of C allows you to quietly treat any type like any other type. • C++ doesn’t allow this

  40. References in C++ • A reference (&) is like a constant pointer that is automatically dereferenced. • It is usually used for function argument lists and function return values. EX: #include <iostream> int y; int& r = y; const int& q = 12; // (1) int x = 0; // (2) int& a = x; // (3) int main() { cout << "x = " << x << ", a = " << a << endl; a++; cout << "x = " << x << ", a = " << a << endl; }

  41. There are certain rules when using references • A reference must be initialized when it is created. (Pointers can be initialized at any time.) • Once a reference is initialized to an object, it cannot be changed to refer to another object. (Pointers can be pointed to another object at any time.) • You cannot have NULL references. You must always be able to assume that a reference is connected to a piece of storage.

  42. References in functions • The most common place you’ll see references is as function arguments and return values. • When a reference is used as a function argument, any modification to the reference inside the function will cause changes to the argument outside the function. • you could do the same thing by passing a pointer, but a reference has much cleaner syntax

  43. #include<iostream.h> int* f(int* x) { (*x)++; return x; // Safe, x is outside this scope } int& g(int& x) { x++; // Same effect as in f() return x; // Safe, outside this scope } int main() { int a = 0; f(&a); // Ugly (but explicit) g(a); // Clean (but hidden) }

  44. Const references • Making the argument a const reference will allow the function to be used in all situations. • This means that, for built-in types, the function will not modify the argument, and for user-defined types, the function will call only const member functions • The use of const references in function arguments is especially important because your function may receive a temporary object. • This might have been created as a return value of another function or explicitly by the user of your function. • Temporary objects are always const, so if you don’t use a const reference, that argument won’t be accepted by the compiler.

  45. EX: void f(int&) {} void g(const int&) {} int main() { //! f(1); // Error g(1); }

  46. The copy-constructor • A copy constructor is used to declare and initialize an object from another object • A copy constructor takes a reference to an object of the same class as itself as an argument • The syntax is: Class-name (class-name &i){ } • We cannot pass the argument by value to a copy constructor

  47. #include<iostream.h> class code { int id; public: code(){ } code(int a) { id=a; } code(code & x) //copy constructor { id=x.id; } void display() { cout<<id; } }; void main() { code a(100); code b(a); //copy constructor code c=a; code d; d=a; a.display(); b.display(); c.display(); d.display(); } Example of copy constructor

  48. Pointers to members • A pointer is a variable that holds the address of some location. • You can change what a pointer selects at runtime, and the destination of the pointer can be either data or a function. • The C++ pointer-to-member follows this same concept, except that what it selects is a location inside a class • EX: struct Simple { int a; }; int main() { Simple so, *sp = &so; sp->a; so.a; }

  49. Operator overloading

More Related