Wednesday, August 13, 2008

Access specification

This topic tells when is contructor called and when not

1.formation of object(lolz)

2.passing objects to the function

class X
{
    int i;
public:
    X(int b)    {            cout<<"love";         i=b;     }
    void  set_i(int b){s=b;}
    put_i()     {         cout<<"i="<<     }
    X()//destructor     {         cout<<"hate"    }
}; // class over

void f(X ob)
{
    ob.set_i(2);//i is now 2
    ob.put_i();
}

int main()
{
    X o(1);//i is 1
    o.put_i();
    f(o);//i is now 2
    o.put_i();
    return 0;
}

This program produces this output
love
i=1
i=2
hate
i=1
hate
Notice that two calls to the destructor function are executed, but only one call is
made to the constructor function. 

As the output illustrates, the constructor function
is not called when the copy of o (in main() ) is passed to ob (within f() ). The reason
that the constructor function is not called when the copy of the object is made is easy to
understand. When you pass an object to a function, you want the current state of that
object. If the constructor is called when the copy is created, initialization will occur,
possibly changing the object. Thus, the constructor function cannot be executed when
the copy of an object is generated in a function call.

Although the constructor function is not called when an object is passed to a
function, it is necessary to call the destructor when the copy is destroyed. (The copy
is destroyed like any other local variable, when the function terminates.) Remember,
a new copy of the object has been created when the copy is made. This means that
the copy could be performing operations that will require a destructor function to
be called when the copy is destroyed. For example, it is perfectly valid for the copy to
allocate memory that must be freed when it is destroyed. For this reason, the destructor
function must be executed when the copy is destroyed.
To summarize: When a copy of an object is generated because it is passed to a
function, the object's constructor function is not called. However, when the copy of the
object inside the function is destroyed, its destructor function is called.
By default, when a copy of an object is made, a bitwise copy occurs. This means
that the new object is an exact duplicate of the original. The fact that an exact copy is
made can, at times, be a source of trouble. Even though objects are passed to functions
by means of the normal call-by-value parameter passing mechanism, which, in theory,
protects and insulates the calling argument, it is still possible for a side effect to occur
that may affect, or even damage, the object used as an argument. For example, if an
object used as an argument allocates memory and frees that memory when it is
destroyed, then its local copy inside the function will free the same memory when its
destructor is called. This will leave the original object damaged and effectively useless.
It is possible to prevent this type of problem by defining
the copy operation relative to your own classes by creating a special type of constructor
called a copy constructor.

3.When the objects are returned by the function

A function may return an object to the caller. For example, this is a valid C++ program:
// Returning objects from a function.
#include
using namespace std;
class myclass {
int i;
public:
void set_i(int n) { i=n; }
int get_i() { return i; }
};// end class
myclass f(); // return object of type myclass
int main()
{
myclass o;
o = f();
cout << o.get_i() << "\n";
return 0;
}
myclass f()
{
myclass x;
x.set_i(1);
return x;
}
When an object is returned by a function, a temporary object is automatically
created that holds the return value.
It is this object that is actually returned by the
function. After the value has been returned, this object is destroyed. The destruction of
this temporary object may cause unexpected side effects in some situations. For
example, if the object returned by the function has a destructor that frees dynamically
allocated memory, that memory will be freed even though the object that is receiving
the return value is still using it. There are ways to overcome this problem that involve
overloading the assignment operator and defining a copy constructor. 


 4.Initialised vs non initialised constructor

class X
{
    int a;
    public;
        X(){a=0;}
        X(int b){b=a;}
};

int main()
{
    X x;//con1
    X x(4);//con2
}

5.Copy constructor
It is important to understand that C++ defines two distinct types of situations in
which the value of one object is given to another. The first is assignment. The second is
initialization, which can occur any of three ways:

  •  When one object explicitly initializes another, such as in a declaration
  •  When a copy of an object is made to be passed to a function
  •  When a temporary object is generated (most commonly, as a return value)
The copy constructor applies only to initializations. For example, assuming a class
called myclass, and that y is an object of type myclass, each of the following statements
involves initialization.
myclass x = y; // y explicitly initializing x
func(y); // y passed as a parameter
y = func(); // y receiving a temporary, return object
Following is an example where an explicit copy constructor function is needed.
This program creates a very limited "safe" integer array type that prevents array
boundaries from being overrun. Storage for each array is allocated by the use of new,
and a pointer to the memory is maintained within each array object.
/* This program creates a "safe" array class. Since space for the array is allocated using new, a copy constructor is provided to allocate memory when one array object is used to initialize another.
*/
#include
#include
#include
using namespace std;
class array {
int *p;
int size;
public:
array(int sz) {
try {
p = new int[sz];
} catch (bad_alloc xa) {
cout << "Allocation Failure\n";
exit(EXIT_FAILURE);
}
size = sz;
}
~array() { delete [] p; }
// copy constructor
array(const array &a);
void put(int i, int j) {
if(i>=0 && i
}
int get(int i) {
return p[i];
}
};
// Copy Constructor
array::array(const array &a) {
int i;
try {
p = new int[a.size];
} catch (bad_alloc xa) {
cout << "Allocation Failure\n";
exit(EXIT_FAILURE);
}
for(i=0; i
}
int main()
{
array num(10);
int i;
for(i=0; i<10; i++) num.put(i, i);
for(i=9; i>=0; i--) cout << num.get(i);
cout << "\n";
// create another array and initialize with num
array x(num); // invokes copy constructor
for(i=0; i<10; i++) cout << x.get(i);
return 0;
}
Let's look closely at what happen s when num is used to initialize x in the statement
array x(num); // invokes copy constructor
The copy constructor is called, memory for the new array is allocated and stored in x.p,
and the contents of num are copied to x's array. In this way, x and num have arrays
that contain the same values, but each array is separate and distinct. (That is, num.p
and x.p do not point to the same piece of memory.) If the copy constructor had not
been created, the default bitwise initialization would have resulted in x and num
sharing the same memory for their arrays. (That is, num.p and x.p would have indeed
pointed to the same location.)
Remember that the copy constructor is called only for initializations. For example,
this sequence does not call the copy constructor defined in the preceding program:
array a(10);
// ...
array b(10);
b = a; // does not call copy constructor



No comments:

Post a Comment