Link to home
Start Free TrialLog in
Avatar of cofactor
cofactor

asked on

can anybody explain copy constructor

hi, i want  to understand the copy constructor.  how it works. i could not understand bcoz  there are weired syntaxes in my book. i think  copy constructor  is a very imporatant feature of C++


can anybody explain copy constructor. i need to understand the basics. if you give pseuodocode along with commentation, it may help to understand.

thanks
Avatar of lakshman_ce
lakshman_ce

A copy constructor creates a new object as a copy of the object that you pass in. As an approximation, it's like creating a new object and using the assignment operator to create a copy of your first object. The copy constructor is mostly  used "behind the scenes" when you copy data into (or return data from) a method, but you can of course use it explicitly in your program.

A copy CTOR is defined like this:

MyObject(const MyObject& o);

You pass in a reference to the object that needs to be copies (if you wouldn't use the reference, you would need a copy constructor, which isn't there yet), and you define the parameter as const, because it does not get modified in the CTOR. The copy CTOR (like a normal CTOR) does not return anything.

For the longer explanation, check out Lakshman's links.
Avatar of cofactor

ASKER

if  i  write
             myclass s = a;  // a,s are objects of myclass

but  DO  NOT  define  constructor   MyObject(const MyObject& o); then will the object be copied by default ???

does it mean compiler has a default copy-constructor  if it dont find the user defined copy constructor like the above syntax ?
sorry two class name is different in my above post(i.e MyObject and myclass)....but u understand what i mean.
In this case, you will use the assignment operator=() and not the copy constructor, the copy constructor is used when you use something like this:

myclass s(a); // a is the already existing object that you want to copy.

The compiler will create both a default assignment operator and a default copy constructor, but both of them will use a byte by byte copy of the source. This will of course cause problems if you have pointers or objects in your source object.
ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>> In this case, you will use the assignment operator=()

No. With

      myclass s = a;      

the copy constructor is called and not the assignment operator=(..).

That is different to this:

        myclass s;
        s = a;         // Here operator=(..) gets called

Note, i forgot a semicolon at end of declaration of class B;

Regards, Alex
>>>"Both cases a copy constructor will called either the one you did provide or a 'default' copy constructor making a copy of the storage. .."

hi, the main motto of copy constructor is to copy data between classes.
 so , why do we define our copy constructor !! why not we take the help from the default copy constructor itself.

i dont know wheteher copy constructor has any other usage other than copying.



P.S > alex you helped me yesterday to find a 3 x 3 box  neighbour of a matrix element.

is it possible to get all the neighbours (i.e 3 x 3 , 5 x 5 , 7 x 7 ) of (i,j)th element of the matrix  using a   LOOP ?

bcoz, currentli i am  writing  all the neighbours manually. if the mask size is bigger then it is very bad to  write  down all the neighbours manually. let  the program find out its  neighbours(3 x 3, 5 x 5, 7 x 7 etc). i think i have to take the help of a loop.

is it possible ? can  you tell some tricks to find out  3 x 3 or 5 x 5 or 7 x 7 box neighbour of a matrix elemnt  using loop or whatever  for efficiency ?


thanks

>> so , why do we define our copy constructor !! why not we take the help from the default copy constructor itself.

As i told you, defaukt constructor is dump and copies all bits. However, you need a 'deep' copy where any pointers get a new storage to point to and not copying a storage that belongs to another member.

is it possible to get all the neighbours (i.e 3 x 3 , 5 x 5 , 7 x 7 ) of (i,j)th element of the matrix  using a   LOOP ?

enum BoxSize { Box_3x3 = 1, Box_5x5 = 2, Box_7x7 = 3 };
 
vector<pair<int, int> >* getNeighbors( int matrixSize, BoxSize bs, int i, int j )
{
     vector<pair<int, int> >* pV = new vector<pair<int, int> >;  // Note there must be a space between > >
     for ( int x = i - bs; x <= i + bs )
     {
         if (x < 0 || x >= matrixSize)
             continue;
         for ( int y = j - bs; y <= j + bs )
         {
               if (y < 0 || y >= matrixSize || (x == i && y == j))
                    continue;
              pV->push_back(pair<int, int>(x, y));
         }
      }
      return pV;
}                    

Tell me if you need more info.

Regards, Alex
 
ohh   God.....i am weak in TEMPLATES  ( advanced data structure ), i was expecting very simple answer , may be in C  . can you change the code in C or in C++ without templates...simply array.


at this stage i am not comfortable in Templates .Anyway, if you can convert using array (may be in C )   it  would be good.

however many thanks....i am trying to understand your code.

thanks

thanks alex....i  think  i am not giving the full material. Let me tell you explicitly what i am doing now.

1.  i have a gaussian mask ( 5 x 5)

                                                        gauss1[5][5] = { {2,4,5,4,2},
                              {4,9,12,9,4},
                              {5,12,15,12,5},
                              {4,9,12,9,4},
                              {2,4,5,4,2}
                              };





2.     and i have a image 512 x 512  



3.    i am moving  this mask    on  pixel to pixel (of course which has 5 x 5 neighbour) of the image  and averaging like below........


      for(i=2;i<510;i++)
      for(j=2;j<510;j++)
    {
      image[i][j] = gauss1[0][0]*image1[i-2][j-2] + gauss1[0][1]*image1[i-2][j-1]+gauss1[0][2]*image1[i-2][j]

            + gauss1[0][3]*image1[i-2][j+1] + gauss1[0][4]*image1[i-2][j+2];
 
        gauss1[1][0]*image1[i-1][j-2] + gauss1[1][1]*image1[i-1][j-1]+gauss1[1][2]*image1[i-1][j]

            + gauss1[1][3]*image1[i-1][j+1] + gauss1[1][4]*image1[i-1][j+2];

           gauss1[2][0]*image1[i][j-2] + gauss1[2][1]*image1[i][j-1]+gauss1[2][2]*image1[i][j]

            + gauss1[2][3]*image1[i][j+1] + gauss1[2][4]*image1[i][j+2];

            gauss1[3][0]*image1[i+1][j-2] + gauss1[3][1]*image1[i+1][j-1]+gauss1[3][2]*image1[i+1][j]

            + gauss1[3][3]*image1[i+1][j+1] + gauss1[3][4]*image1[i+1][j+2];

        +gauss1[4][0]*image1[i+2][j-2] + gauss1[4][1]*image1[i+2][j-1]+gauss1[4][2]*image1[i+2][j]

            +gauss1[4][3]*image1[i+2][j+1] + gauss1[4][4]*image1[i+2][j+2];
      }
 
 

and replacing the centre elemnt by the  sum  value....


my question
-----------------

can i make the above code compact , shorter ?? this is my purpose.  
thanks





I remember you only wanted neighbors that have an Image pointer not equal to NULL??

Ok.

#include <iostream>

enum BoxSize { Box_3x3 = 1, Box_5x5 = 2, Box_7x7 = 3 };

class Image
{
   void* pImg;
public:
   Image() : pImg(NULL) {}
};

struct Cell
{
    int x;
    int y;
    Cell(int xx, int yy) : x(xx), y(yy) {}
    Cell() : x(-1), y(-1) {}
    bool isValid() { return (x >= 0 && y >= 0); }
};

#define MATRIX_SIZE 1024

typedef Image*  ImageMatrix[MATRIX_SIZE][MATRIX_SIZE];
 
Cell* getNeighbors( ImageMatrix& matrix, int matrixSize, BoxSize bs, int i, int j )
{
     Cell* pNeighbors = new Cell[(bs+2)*(bs+2)];  // the array size is one greater than we need. The last cell always is invalid, thus terminating the array
     int count = 0;
     for ( int x = i - bs; x <= i + bs; x++ )
     {
         if (x < 0 || x >= matrixSize)
             continue;
         for ( int y = j - bs; y <= j + bs; y++ )
         {
               if (y < 0 || y >= matrixSize || (x == i && y == j))
                    continue;
               if (matrix[x][y] == NULL)
                    continue;
               pNeighbors[count].x = x;
               pNeighbors[count].y = y;
               count++;
         }
      }
      return pNeighbors;
}                    

// You may use it like this:

void main()
{
      ImageMatrix matrix = { NULL };
      // fill matrix somehow
      //....
      // get i, j from somewhere
      //...
      int i = 17;
      int j = 253;

      // get all neighbors of a 5x5 box  
      Cell* neighbors = getNeighbors(matrix, MATRIX_SIZE, Box_5x5, i, j);

     int count = 0;
     while ( neighbors[count].isValid() )
     {
          int x = neighbors[count].x;
          int y = neighbors[count].y;
          // now x, y are the coordinates of a valid neighbor
          // ....
         
          count++;
     }
     delete [] neighbors;
}



BTW, you must not be good in templates, just use them.  What i've used in my first example was a vector - that is a dynamic array - of integer pairs, where one pair holds the x, y coordinates of one of the neighbors. Without template classes i had to create a new struct/class called Cell that does the same as pair<int, int> - or better that does less. Furthermore, i had to define a 'isValid' function to be able to find out when there are no more Cell elements left in array.

Hope, that helps

Alex




Sorry, i missed your last comment. So my last comment answers your previous question (Gauss isn't involved yet).

I'll  need some more minutes as i try to compile the solution before posting.

Regards, Alex
 

#include <iostream>

enum BoxSize { Box_3x3 = 1, Box_5x5 = 2, Box_7x7 = 3 };

#define MATRIX_SIZE 512

typedef int ImageMatrix[MATRIX_SIZE][MATRIX_SIZE];
 

// You may use it like this:

void main()
{
     ImageMatrix image = { NULL };
      // fill matrix somehow
      //....
     int gauss5[5][5] =
     {
         {2,4,5,4,2},
         { 4,9,12,9,4},
         {5,12,15,12,5},
         {4,9,12,9,4},
         {2,4,5,4,2}
     };
     

     int i, j, x, y;
     BoxSize bs = Box_5x5;
     
     for(i = bs; i < MATRIX_SIZE - bs; i++)
     {
         for(j = bs; j < MATRIX_SIZE - bs; j++)
         {
             int temp = 0;
             for ( x = i - bs; x <= i + bs; x++ )
             {
                 for ( y = j - bs; y <= j + bs; y++ )
                 {
                     temp += gauss5[x - (i - bs)][y - (j - bs)] * image[x][y];
                 }
             }
             image[x][y] = temp;
         }
     }
}

Note, now it is only a solution for a 5x5 box. However, if you would provied gauss numbers for 3x3 and 7x7 also, you can make the loop independent of the size of the box by this:

#include <iostream>

enum BoxSize { Box_3x3 = 1, Box_5x5 = 2, Box_7x7 = 3 };

#define MATRIX_SIZE 512

typedef int ImageMatrix[MATRIX_SIZE][MATRIX_SIZE];
 

// You may use it like this:

void main()
{
     ImageMatrix image = { NULL };
      // fill matrix somehow
      //....
     int gauss_3x3[9]   =
     {  1, 2, 1,
         2, 4, 2,
         1, 2, 1
     };
     int gauss_5x5[25] =
     {
          2,4,5,4,2,
         4,9,12,9,4,
         5,12,15,12,5,
         4,9,12,9,4,
         2,4,5,4,2
     };
     int gauss_7x7[49] =
     {
         2,4,5,9,5,4,2,
         4,9,12,15,12,9,4,
         5,12,15,21,15,12,5,
         7,17,25,31,25,17,7,
         5,12,15,21,15,12,5,
         4,9,12,9,4,
         2,4,5,4,2
     };
     
    int* gauss[3] = { gauss_3x3, gauss_5x5, gauss_7x7 };  

     int i, j, x, y;
     BoxSize bs = Box_5x5;
     
     for(i = bs; i < MATRIX_SIZE - bs; i++)
     {
         for(j = bs; j < MATRIX_SIZE - bs; j++)
         {
             int temp = 0;
             for ( x = i - bs; x <= i + bs; x++ )
             {
                 for ( y = j - bs; y <= j + bs; y++ )
                 {
                     temp += gauss[bs-1][(x - (i - bs))*(2*bs+1) + y - (j - bs)] * image[x][y];
                 }
             }
             image[x][y] = temp;
         }
     }
}

Regards, Alex


 
ok, thansk alex....i am reading  your  code... i need some time to see what u r doing...i will reply soon.

thanks
sorry there was a typo in my earlier post in that big equn.

it should be.... image1[i][j] = gauss1[0][0]*image1[i-2][j-2] ....//  bla   bla..(NOT image[i][j])

>> image1/image
That doesn't matter. I called it image and as it compiled the compiler was happy with that name ;-)

Will give you some remarks on my code:

>> enum BoxSize { Box_3x3 = 1, Box_5x5 = 2, Box_7x7 = 3 };
That enum BoxSize are only integer constants. Maybe i should have called it better BoxRadius as it is the number of neighbors in any direction.

>>typedef int ImageMatrix[MATRIX_SIZE][MATRIX_SIZE];

That typedef makes it possible to pass the matrix to a function (as pointer or as reference) and use image[x][y] within the function. You should know that in C/C++ arrays are passed to functions as pointers. Th at means the array dimensions get lost and you would get a compiler error when using image[x][y] as the compiler doesn't know the size of the matrix. Using a typedef gives this information.

>>    int* gauss[3] = { gauss_3x3, gauss_5x5, gauss_7x7 };  

I made a new array, where i stored the pointers to all (three) gaussian arrays. Thus  gauss[0] == gauss_3x3, gauss[1] == gauss_5x5, gauss[2] == gauss_7x7

>> BoxSize bs = Box_5x5;

With that i made the loop independent of the box size; you may choose other Box values here and the loop must not be changed.

>> for(i = bs; i < MATRIX_SIZE - bs; i++)

The loop starts with bs == 2 and ends before MATRX_SIZE-bs == 510.

>>          int temp = 0;

As the box calculations were done in a loop i need a temporary integer where the sum can be added.

>>              temp += gauss[bs-1][(x - (i - bs))*(2*bs+1) + y - (j - bs)] * image[x][y];

That's maybe difficult? Ok, step by step:

>> gauss[bs-1]        

You know bs == 2, so we are using gauss[1] == gauss_5x5.

>> (x - (i - bs))

x runs from i - bs to i + bs. So, at the beginning  (x - (i - bs)) == 0 and finally it is (i + bs - (i - bs)) == (i + bs - i + bs) == bs + bs == 4. Sp the first term runs from 0 to 4 what is the x dimension of the 5x5 gauss array.

>> *(2*bs+1)
That term evaluates to (2*2+1) == 5, what is the box size. As i turned the 5x5 matrix to an array of size 25, i have to calculate the index using  a * boxsize + b, where a == (x - (i - bs)) as described before and

>> (y - (j - bs))

is b. So, all that algorithm i a simple index calculation. BTW, are you good in mathematics?

Hope, it is clear now.

Regards, Alex


 



Regards, Alex

thanks alex, you  have caught me...you are right .exactly  i had problems on those typical areas.so, i was thinking and taking time.

by the time, i liked your first code( 5x 5 only) bcoz it was very simple and i went ahead to implement on my data.......but my  output data file   is not consistent which should not be theoretically.

ok, i am gving the code below....

[code]

#include<iostream>
#include<cstdlib>
#include<fstream>
using namespace std;

#define  MATRIX_SIZE  512

int main()
{
 
      ifstream fin("c:\\lena1.pgm");
      ofstream fout("c:\\filtered_image.pgm");
    int x;
    static int image[512][512];
 
      if(!fin.is_open() ) { cout<<"error"; return EXIT_FAILURE; }
      
      for(int i=0;i<512;i++)
      for(int j=0;j<512;j++)
   
    {
            fin>>x;
      
        image[i][j]= x; // load the image
            
      }
  int gauss5[5][5] =
     {
         {2,4,5,4,2},
         { 4,9,12,9,4},
         {5,12,15,12,5},
         {4,9,12,9,4},
         {2,4,5,4,2}
     };




enum BoxSize { Box_3x3 = 1, Box_5x5 = 2, Box_7x7 = 3 };

     int j,y;
     BoxSize bs = Box_5x5;
     
     for(i = bs; i < MATRIX_SIZE - bs; i++)
     {
         for(j = bs; j < MATRIX_SIZE - bs; j++)
         {
             int temp = 0;
             for ( x = i - bs; x <= i + bs; x++ )
             {
                 for ( y = j - bs; y <= j + bs; y++ )
                 {
                     temp += gauss5[x - (i - bs)][y - (j - bs)] * image[x][y];
                 }
             }
             image[i][j] = temp/115; // 115 is the normalization factor of the 5 x5 matrix
         }
     }




for(int k =0;k<512;k++)
for(int l=0;l<512;l++)
{
 fout<<"\t"<<image[i][j];

}
 



}
[/code]


my output
------------

i am getting  output data file  which is full of only integer number 105 ..i.e there are all  total 512 x 512 integers. each of them are  105  . is not it strange ? it should  not be theoretically. my implementation has gone wrong. i could not find out whats wrong in my code.

but Definitely something wrong in the code bcoz output file can not have all the same numbers. can you suggest what could be wrong in the above code ?


thanks,  i am  concentrating on your new comments and waiting for reply.

P.S : i have changed image[x][y]  to image[i][j] bcoz i will change the centre pixel of the box by the new value.

That's easy. look at your output loop; your counters are k and l while youtur output indexes are i and j.

for(int k =0;k<512;k++)
for(int l=0;l<512;l++)
{
 fout<<"\t"<<image[i][j];

}

Change line to

 fout<<"\t"<<image[k][l];

and it should work. Depending on input file hasn't all the same integer though ;-)

Regards, Alex


Regards, Alex

BTW, you could easily change to the 'advanced' solution, that will most likely produce same output.



>> P.S : i have changed image[x][y]  to image[i][j] bcoz i will change the centre pixel of the box by the new value.

Good, that was a copy-paste error that i made...

>> #define  MATRIX_SIZE  512

You should replace 512 by MATRIX_SIZE, that is good practice and makes it easier to change sizes.

Regards, Alex



 
>>That's easy. look at your output loop; your counters are k and l while youtur output indexes are i and j.

ooops....i did not  notice  it . ok  thanks. i will fix it.

>>Depending on input file hasn't all the same integer though.

 input file is perfectly valid. and good looking image having numbers in between 0-255. its ok.

i will try tomorrow to fix .


>>you could easily change to the 'advanced' solution, that will most likely produce same output.
 
i need some time to sleep  now . tomorrow morning i will go for the advanced soln and fix  the above  errors.

thanks
 

hi alex,

  i have fixed the erros. and implemented on my image data and got filtered image .implementation is ok. it is working perfectly.

i have taken up your old soln and  added some  codes also.
one more thing i want make the code smarter.

CAN i do a use-interactivity with code ? so that the user will input what box size he wants.

i want something like below...of course it is not working


int x;
cout<<"plz enter the BOXSIZE  number..... 1 (for 5x5)  , 2  (for 7x 7) "<<endl;
cin>>x;
BoxSize bs = x   //  here is the problem...compiler gives error... .enum and int are conflicting

which way i would write so that user can give his choice.

thanks




 

enum BoxSize { Box_Invalid = -1, Box_3x3 = 1, Box_5x5 = 2, Box_7x7 = 3 };

BoxSize bs = Box_Invalid;
int x;

while (bs == Box_Invalid)
{
   cout<<"plz enter the BOXSIZE  number..... 5 (for 5x5)  ,  7 (for 7x 7) "<<endl;
   cin>>x;
   bs = (x == 5)?  Box_5x5 : (x == 7)? Box_7x7 : Box_Invalid;
   if (bs == Box_Invalid)
   {
       cout << "It isn't difficult to enter either 5 or 7, try again.." << endl;
   }
}

Regards, Alex

bravo, great....you have tackled very clever way. now i see there will be no data type conflict.
this must work certainly.

i read your advanced solution....i am getting the points.
can i ask you one  more silly question.

you have written
int* gauss[3] = { gauss_3x3, gauss_5x5, gauss_7x7 };  

is it a valid syntax ?  bcoz your content of the array are matrices. so my recomendation is

int**  gauss[3] = { gauss_3x3, gauss_5x5, gauss_7x7 };   // double *

bcoz matrix is written   int ** matrix.

i  am not sure whether i am correct in this context .

anyway, thanks for the clarification, solution and great help.
is it a valid syntax ?

My Compiler said, yes.

Look at the definition of gauss_3x3, ...   I serialized them to an array, just adding line by line.

The reason for this was to be able to put them into that gauss[] array. If i have three matrices, each different in the x size, i wouldn't be able to store them to a common array. But i need t that array for this statement:

      temp += gauss[bs-1][(x - (i - bs))*(2*bs+1) + y - (j - bs)] * image[x][y];

if i had three matrices i would have change it to

      if (bs == Box_3x3)
            temp += gauss_3x3[x-(i-bs)][y-(i-bs];
      else if (bs == Box_5x5)
            temp += gauss_5x5[x-(i-bs)][y-(i-bs];
      else
            temp += gauss_7x7[x-(i-bs)][y-(i-bs];

Not bad, but the other is better.

Regards, Alex