Constructors

Default arguments
- Any C++ function can provide default values for its input function arguments

- If a value is not specified in a function call, the default value is assigned and sent to the called function

- Consider the following example with a standard (non-class member) function

 

#include <iostream>

using namespace std;

 

int add( int a=10, int b=2 );

 

main()

{

  int f1 = add();

  cout << f1 << endl;

}

 

int add( int a, int b )

{

  return (a+b);

}

 

Output

12

 

- When the compiler processes the add function it does not “see” any values provided for the two arguments

- As a result, it assigns the default values, 10 and 2, to a and b when calling the function

- Users, however, can override the default values by providing their own values in the function call

- As a result, the same function can look very different when it is called

 

main()

{

  int f1 = add();

  int f2 = add( 14, 7);

  cout << f1 << “ “ << f2 << endl;

}

 

Output

12 21

 

- Default values are optional and not required for every function argument

- For multiple arguments, however, a rule must be enforced for default values or the compiler might get confused

- Consider the following scenario

 

#include <iostream>

using namespace std;

 

int add( int a=10, int b );

 

main()

{

  int f1 = add( 20 );

  cout << f1 << endl;

}

 

int add( int a, int b )

{

  return (a+b);

}

 

- When the compiler encounters the function call, which argument (a or b) should it assign the value 20?

- Should it override the value 10 and assign it to a or should it be assigned to b?

- Obviously, this is indeterminate and cannot be resolved by the compiler

- In fact, this code example will not compile and report the following errors

 

error: default argument missing for parameter 2 of `int add(int, int)'

In function `int main()':

error: too few arguments to function `int add(int, int)'

error: at this point in file

In function `int add(int, int)':

error: default argument missing for parameter 2 of `int add(int, int)'

 

- To clear up the confusion, a rule is enforced when using default values and multiple arguments

- All arguments to the right of an argument with a default value must be specified
- In other words, their can be no "holes" in your default parameter list

- This rule helps the compiler determine which arguments to assign values to in a function call

- Correcting our example according to this rule, we now have the following

 

#include <iostream>

using namespace std;

 

int add( int a, int b=2 );

 

main()

{

  int f1 = add( 20 );

  cout << f1 << endl;

}

 

int add( int a, int b )

{

  return (a+b);

}

 

Output

22

 

- With this rule, values specified will be assigned to arguments beginning from the left

- In this example, the value 20 is assigned to a and the default value 2 is assigned to b

- Consider another example with an added function argument

- In this example, we have provided a default value for b but not for c

 

#include <iostream>

using namespace std;

 

int add( int a, int b=2, int c );

 

main()

{

  int f1 = add( 20 );

  cout << f1 << endl;

}

 

int add( int a, int b, int c )

{

  return (a+b+c);

      }

 

- Since we have not specified a value for c according to the rule, the compiler reports the following error

 

            error: default argument missing for parameter 3 of 'int add(int, int, int)'

 

- The rule states we must provide a default value for all arguments to the right of the first one with a default value

- The first argument with a default value is b, so we must provide a default value for argument c

- Correcting our program, we have the following

 

#include <iostream>

using namespace std;

 

int add( int a, int b=2, int c=4 );

 

main()

{

  int f1 = add( 20 );

  cout << f1 << endl;

}

 

int add( int a, int b, int c )

{

  return (a+b+c);

      }

 

Output

      26

 

 

Constructors
- Special type of class member function   

- Automatically called upon object instantiation  

- Same name as the class
- No return type
- Arguments allowed, can have default arguments

- Consider the following class definition for a three-dimensional point in space

- A constructor is defined inline (definition included with declaration) with default argument values

 

#include <iostream>

using namespace std;

 

class Point

{

private:

  float x, y, z;

 

public:

  Point(float c1=0.0, float c2=0.0, float c3=0.0)

  {

    x = c1;

    y = c2;

    z = c3;

  }

  void Print()

  {

    cout << "x y z: “ << x << “ “ << y << “ “ << z << endl;

  }

};

 

- Constructors provide an ideal place to perform any initial housekeeping tasks associated with objects

- Such tasks could include allocating memory, opening files, or initializing state variables (as in the example above)

- Recall that constructors are automatically called when objects are instantiated

- As a result, such initial housekeeping tasks will be performed when each object is declared

- This provides an ideal mechanism for assuring that objects will be created correctly when called in programs

- Object declarations (or instantiations) can look different when using default argument values

- In the example below, two Point objects are instantiated with different x,y,z values

 

main()

{

  Point p;

  p.Print();

 

  Point p1( 0.0, 2.0, 3.0 );

  p1.Print();

}

 

Output

x y z: 0.00 0.00 0.00

x y z: 0.00 2.00 3.00

- State variables cannot be initialized in declarations in the class definition as follows

#include <iostream>

using namespace std;

 

class Point

{

private:

  float x = 0.0;

  float y = 0.0;

  float z = 0.0;

 

public:

  Point(float c1=0.0, float c2=0.0, float c3=0.0)

  {

    x = c1;

    y = c2;

    z = c3;

  }

  void Print()

  {

    cout << "x y z: “ << x << “ “ << y << “ “ << z << endl;

  }

};

- This code is will not compile and reports the following errors

error: ISO C++ forbids initialization of member `x'

error: making `x' static

error: ISO C++ forbids in-class initialization of non-const static

   member `x'

error: ISO C++ forbids initialization of member `y'

error: making `y' static

error: ISO C++ forbids in-class initialization of non-const static

   member `y'

error: ISO C++ forbids initialization of member `z'

error: making `z' static

error: ISO C++ forbids in-class initialization of non-const static

   member `z'

- Instead, Initialization should be done in the constructor (or in functions called by the constructor)

 

Object Declarations
- Constructors can be called (through object instantiation) in several different ways

- Consider the example below using our Point class

 

main()

{

  Point p1;

  Point p2( 1.0, 2.0, 3.0 );

  Point p3 = Point( 4.0, 5.0, 6.0);

  Point *p4 = new Point();

  Point *p5 = new Point( 7.0, 8.0, 9.0 );

 

  p1.Print();

  p2.Print();

  p3.Print();

  p4->Print();

  p5->Print();

}

 

Output

x y z: 0.00 0.00 0.00

x y z: 1.00 2.00 3.00

x y z: 4.00 5.00 6.00

x y z: 0.00 0.00 0.00

x y z: 7.00 8.00 9.00

 

- Note the various methods of instantiation
- The constructor for objects
p1 and p2 are implicitly called with a "shorthand" form
- The constructor for object
p3 is explicitly called with a "longhand" form which returns references to the object
- Note this is implied (no return type in declaration)

- Objects p4 and p5 are dynamically allocated using the new operator differing in default argument values

 

 

 

Constructor Overloading
- Multiple versions of constructor functions can be written each with the same name but different arguments

- The constructor functions differ only in their input parameter lists (types and number of arguments)

- This concept is referred to as function overloading and plays a key role in object-oriented methodologies

- As we’ll see in detail later, function overloading can be applied to any type of function in C++

- Consider the following example with an extended version of the Point class

 

#include <iostream>

using namespace std;

 

class Point

{

private:

  float x,y,z;

 

public:

  Point(float c1=0.0, float c2=0.0, float c3=0.0)

  {

    x = c1;

    y = c2;

    z = c3;

  }

  Point(float *c)

  {

    x = c[0];

    y = c[1];

    z = c[2];

  }

  void Print()

  {

    cout << "x y z: “ << x << “ “ << y << “ “ << z << endl;

  }

};

 

- In this example, we have two constructor functions differing by their input parameter list

- This first constructor accepts three floating point variables in its parameter list

 

Point(float c1=0.0, float c2=0.0, float c3=0.0)

  {

    x = c1;

    y = c2;

    z = c3;

  }

 

- While the second constructor accepts a pointer to an array of floating point variables

 

Point(float *c)

  {

    x = c[0];

    y = c[1];

    z = c[2];

  }

 

- Objects can be constructed in different ways depending on the type of argument list used in a program

- Below the first constructor is called for objects p1 and p2 and the second constructor is called for p3

- In this way, constructor overloading provides class users more flexible ways of declaring objects

 

main()

{

  float a = 1.0;

  float b = 2.0;

  float c = 3.0;

  float d[3] = { 4.0, 5.0, 6.0 };

 

  Point p1;

  Point p2( a, b, c );

  Point p3( d );

 

  p1.Print();

  p2.Print();

  p3.Print();

}

 

Output

x y z: 0.00 0.00 0.00

x y z: 1.00 2.00 3.00

x y z: 4.00 5.00 6.00