Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ Programming ➜ General ➜ C++, constructors, copying, assignment

C++, constructors, copying, assignment

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Nick Gammon   Australia  (23,158 posts)  Bio   Forum Administrator
Date Sat 10 Jul 2004 04:13 AM (UTC)

Amended on Wed 13 Apr 2016 12:40 AM (UTC) by Nick Gammon

Message
Also see:

http://www.gammon.com.au/forum/?id=11105

for details about a walkthrough of making a C++ class.




Tracing class construction

Before pressing on with concrete examples of creating C++ objects, I will present a small "trace" class that lets us see when objects are being created and destroyed.

This class can be used as a base class for other classes, or inserted into a different class.



#include <iostream>

using namespace std;

template <char id = 'X'>
class obj_trace
  {
  public:
    // default constructor
    obj_trace () : which (++count)
      {
      cout << "object " << id << which << " constructed" << endl;
      }

    // destructor
    ~obj_trace ()
      {
      cout << "object " << id << which << " destroyed" << endl;
      }

    // copy constructor
    obj_trace (const obj_trace & rhs) : which (++count)
      {
      cout << "object " << id << which << " copy constructed" << endl;
      }

    // operator=  (assignment)
    obj_trace & operator= (const obj_trace & rhs)
      {
      cout << "object " << id  << which << " operator=" << endl;
      return *this;
      }

  private:

    static int count;   // count of this type of object
    int which;          // which one this is
  };  // end of obj_trace


template <> int obj_trace<'A'>::count = 0;
template <> int obj_trace<'B'>::count = 0;
template <> int obj_trace<'C'>::count = 0;
template <> int obj_trace<'D'>::count = 0;

class A : public obj_trace<'C'>
  {
  int x;
  };

class B
  {
  obj_trace<'D'> y;
  };

int main (void)
  {
  cout << "creating a, b" << endl;
  obj_trace<'A'> a, b;
  cout << "creating c, d" << endl;
  obj_trace<'B'> c, d;
  cout << "creating: A e" << endl;
  A e;
  cout << "creating: B f" << endl;
  B f;

  cout << "program end" << endl;
  return 0;
  }



Output



creating a, b
object A1 constructed
object A2 constructed
creating c, d
object B1 constructed
object B2 constructed
creating: A e
object C1 constructed
creating: B f
object D1 constructed
program end
object D1 destroyed
object C1 destroyed
object B2 destroyed
object B1 destroyed
object A2 destroyed
object A1 destroyed


The obj_trace class is templated to take a letter which indicates which type it is (eg. class A or class B and so on).

Each type (eg. class A) maintains a static count so you can see how many types of that class are created, and which order they are created/destroyed.

The program above illustrates the various way of using the obj_trace class:


  • Directly, like this:

    
      obj_trace<'A'> a;
    


  • To derive a class from, like this:

    
    class A : public obj_trace<'C'>
      {
      int x;
      };
    


    Doing this will tell you when the class (class A in this case) is constructed/destroyed.

  • To insert inside a class (or function), like this:

    
    class B
      {
      obj_trace<'D'> y;
      };
    


    Doing this will tell you when the class's members (variable y in this case) area constructed/destroyed.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,158 posts)  Bio   Forum Administrator
Date Reply #1 on Sat 10 Jul 2004 04:35 AM (UTC)

Amended on Sat 10 Jul 2004 04:40 AM (UTC) by Nick Gammon

Message
I've been playing with C++ a bit recently and am trying to define exactly what happens when you make classes and try to copy them. Do things get initialised? Do they get copied?
Try my quiz here and see how you go ...



Test program


#include <iostream>
#include "obj_trace.h"  // code in bold in previous post

using namespace std;
    
// zero counts of object types
int obj_trace<'A'>::count = 0;
int obj_trace<'B'>::count = 0;
      
class A : obj_trace<'A'>
  {
  }; // end of class A

class B : obj_trace<'B'>
  {

  public:

  A a;    // B contains an instance of A
  int i;  // also a simple integer

  };  // end of class B

int main (void)
  {

  // to be supplied - see questions below

  cout << endl << "end of program" << endl;
  return 0;
  }





Quiz 1 - constructors

Given a class "A" which does something (see above), and also given a class "B" that contains A and a normal int (see above):

If I create an instance of B, like this:


int main (void)
  {
  cout << "Doing: B b;" << endl;
  B b;
  cout << endl << "end of program" << endl;
  return 0;
  }


Question 1

Is the instance of class A (inside B) called "a" initialised (by calling its constructor)?

a) Yes - its default constructor is called

b) No - it is not

Question 2

Is the int i (inside B) initialised to zeroes?

a) Yes - it is now zero

b) No - its value is undefined




Answers to Quiz 1

Question 1

The answer is (a) - the constructor for classes inside another class are called when the enclosing class is created.

Question 2

The answer is (b) - simple types (not classes) are not initialised and thus their contents are undefined.

Output from sample program

Doing: B b;
object B1 constructed   <-- b is constructed first
object A1 constructed   <-- member variable a is constructed next
b.i = -858993460        <-- i is not initialised

end of program
object A1 destroyed
object B1 destroyed




Quiz 2 - copy construction

Given the above classes, if I now make another instance of B using the copy constructor idiom (line in bold below) ...


int main (void)
  {
  cout << "Doing: B b;" << endl;
  B b;  // make a B

  b.i = 42;

  cout << "Doing: B c (b);" << endl;
  B c (b);  // make another B

  cout << "c.i = " << c.i << endl;

  cout << endl << "end of program" << endl;
  return 0;
  }


Question 3

What happens to c.a (the value of the class A in the new copy c)?

a) It is not copied and is thus undefined

b) A bitwise copy is made (so c.a is the same as b.a) however neither the constructor nor the operator= for A is called

c) The default constructor for A is called to initialise c.a to whatever value the default constructor wants

d) The copy constructor for A is called to make a copy of it

e) The assignment operator (operator=) for a is called to assign it.

Question 4

What happens to c.i (the value of the int in the new copy c)?

a) It is not copied and is thus undefined

b) It is zero

c) It is the same as in b.i (in this case, 42)

Answers to Quiz 2

Question 3

The answer is (d) - the copy constructor for enclosed classes are called for each one

Question 4

The answer is (c) - simple types (not classes) are copied as well.

Output from sample program

Doing: B b;
object B1 constructed       <-- b is constructed first
object A1 constructed       <-- then member a
Doing: B c (b);
object B2 copy constructed  <-- copy constructor called for c
object A2 copy constructed  <-- copy constructor for member a in c
c.i = 42                    <-- i is copied too

end of program
object A2 destroyed
object B2 destroyed
object A1 destroyed
object B1 destroyed




Quiz 3 - assignment

Given the above classes, if I now make another instance of B by using the assignment operator like this (in bold):


int main (void)
  {
  cout << "Doing: B b;" << endl;
  B b;  // make a B

  b.i = 42;

  cout << "Doing: B c;" << endl;
  B c;  // make another B
  cout << "Doing: c = b;" << endl;
  c = b;   // copy b to c

  cout << "c.i = " << c.i << endl;

  cout << endl << "end of program" << endl;

  return 0;
  }


Question 5

What happens to c.a (the value of the class A in the new copy c)?

a) It is not copied and is thus undefined

b) A bitwise copy is made (so c.a is the same as b.a) however neither the constructor nor the operator= for A is called

c) The default constructor for A is called to initialise c.a to whatever value the default constructor wants

d) The copy constructor for A is called to make a copy of it

e) The assignment operator (operator=) for a is called to assign it.

Question 6

What happens to c.i (the value of the int in the new copy c)?

a) It is not copied and is thus undefined

b) It is zero

c) It is the same as in b.i (in this case, 42)

Answers to Quiz 3

Question 5

The answer is (e) - the operator= for enclosed classes are called for each one

Question 6

The answer is (c) - simple types (not classes) are copied as well.

Output from sample program

Doing: B b;
object B1 constructed  <-- same as before
object A1 constructed
Doing: B c;
object B2 constructed  <-- same as before
object A2 constructed
Doing: c = b;
object B2 operator=    <-- operator= called for c
object A2 operator=    <-- operator= called for member a in c
c.i = 42               <-- i copied as well

end of program
object A2 destroyed
object B2 destroyed
object A1 destroyed
object B1 destroyed




Quiz 4 - construction with assignment

If I make another copy called c, but initialise it in the same statement like this:


int main (void)
  {
  cout << "Doing: B b;" << endl;
  B b;  // make a B

  b.i = 42;

  cout << "Doing: B c = b;" << endl;
  B c = b;  // make another B

  cout << "c.i = " << c.i << endl;

  cout << endl << "end of program" << endl;

  return 0;
  }


Question 7

Is the behaviour here the same as:

a) Copy construction (so the copy constructor for A will be called, like in quiz 2)

b) Assignment (so the operator= for A will be called, like in quiz 3)

c) A bitwise copy (so no constructors will be called)

d) No copying

Answers to Quiz 4

Question 7

The answer is (a) - the copy constructors will be called, despite the fact that it looks like an assignment statement.

Output from sample program

Doing: B b;
object B1 constructed
object A1 constructed
Doing: B c = b;
object B2 copy constructed  <-- copy constructor called, not operator=
object A2 copy constructed  <-- ditto
c.i = 42

end of program
object A2 destroyed
object B2 destroyed
object A1 destroyed
object B1 destroyed

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


12,908 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.