csudha said:
Hello. I note from the other responses to your article that some people
have very funny ideas about topicality. Oh well, can't be helped.
Can you please explain me the usage of copy constructor and how do we use it.
Of course. Glad to oblige.
We use a copy constructor when we wish to create a new object that is
an exact copy of an existing object. This is particularly useful in
situations where we don't wish to expose the inner data of the
object ("data hiding"), or where our object contains pointers to
dynamic data (so that merely duplicating the object representation
of the object would create a danger of a "dangling pointer" when we
are cleaning up).
Sure. The following example has been compiled and tested under
bcc32 (Borland C++ 5.3, invoked in topical mode) and gcc (again
in topical mode), and gave no diagnostics under either compiler
(under gcc, the flags -W -Wall -ansi -pedantic -O2 were used).
The program's output can be found at the end of this reply.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct T_
{
int this;
int that;
char *theother;
};
/* helper routine for a "deep copy" */
char *sduplicate(const char *s)
{
char *new = NULL;
if(s != NULL)
{
new = malloc(strlen(s) + 1);
if(new != NULL)
{
strcpy(new, s);
}
}
return new;
}
typedef struct T_ T;
/* first, a destructor */
void TDestroy(T **old)
{
if(old != NULL)
{
if(*old != NULL)
{
free((*old)->theother);
free(*old);
*old = NULL;
}
}
}
/* now, an ordinary constructor */
T *TCreate(int this, int that, const char * theother)
{
T *new = malloc(sizeof *new);
if(new != NULL)
{
new->this = this;
new->that = that;
new->theother = sduplicate(theother);
if(new->theother == NULL)
{
/* if we can't build it properly,
don't build it at all! */
TDestroy(&new);
}
}
return new;
}
/* now we can code a nice simple copy constructor */
T *TCreateCopy(const T* old)
{
return TCreate(old->this, old->that, old->theother);
}
int TModifyString(T *p, const char *new)
{
int rv = 1; /* error */
if(p != NULL && new != NULL)
{
char *q = sduplicate(new);
if(q != NULL)
{
free(p->theother);
p->theother = q;
rv = 0; /* success */
}
}
return rv;
}
/* proof of purchase */
int TPrint(FILE *fp, T *p)
{
int rv = 0;
if(fp != NULL && p != NULL)
{
rv = fprintf(fp,
"%d %d %s\n",
p->this,
p->that,
p->theother);
}
return rv;
}
/* test driver */
int main(void)
{
T *p = TCreate(123, 456, "hello, world");
if(p != NULL)
{
T *q = TCreateCopy(p);
if(q != NULL)
{
fputs("p = ", stdout);
TPrint(stdout, p);
fputs("q = ", stdout);
TPrint(stdout, q); /* show that the copy worked */
puts("Modifying p now");
if(TModifyString(p, "goodbye, world") == 0)
{
fputs("p = ", stdout);
TPrint(stdout, p);
fputs("q = ", stdout);
TPrint(stdout, q); /* show that q is unaffected by the change
to p, ie a "deep copy" was done */
}
TDestroy(&q);
}
TDestroy(&p);
}
return 0;
}
The output from this program is:
p = 123 456 hello, world
q = 123 456 hello, world
Modifying p now
p = 123 456 goodbye, world
q = 123 456 hello, world
HTH. HAND.