Delegated Constructors

closed account (EwCjE3v7)
I am confused about delegated constructors, as you can see when I supply a string to the class, it calls the first constructor first, then the second one. I do not know why. Shouldnt it be the vice versa

MY CLASS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  #ifndef SALES_DATA_H
#define SALES_DATA_H

#include <iostream>
#include <string>

class Sales_data; // declaration for the following class

std::istream &read(std::istream &, Sales_data &); // declaration for read, used inside the class

class Sales_data {
public:
  friend std::istream &read(std::istream &, Sales_data &);
  friend std::ostream &print(std::ostream &, const Sales_data &);
  friend Sales_data add(const Sales_data &, const Sales_data &);

  // CONSTRUCTORS
  Sales_data() = default; // needed

  Sales_data(const std::string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue (p*n) {std::cout << "1" << std::endl;} // if we get a string, unsigned and a double then initialize the members of the class

  Sales_data(const std::string &s) : Sales_data(s, 0, 0) {std::cout << "2" << std::endl;} // if we just get a string as a initializer then assign that to bookNo

  Sales_data(unsigned n, double p) : Sales_data("", n, p) {std::cout << "3" << std::endl;}


  Sales_data(std::istream &is) // if we get an istream
  {
    read(is, *this); // call read to assign the current object
  }


  std::string isbn() const // funtion to call for the ISBN of the current book
  {
   	 return bookNo; // return the book numbers
  }

  Sales_data& combine (const Sales_data&rhs) // to combine two Objects of Sales_data
  {
  	units_sold += rhs.units_sold; // add the amount of books sold
  	revenue += rhs.revenue;       // for adding the revenue
  	return *this;                 // return the object that the funtion was called on
  }

private:
	inline double avg_price() const // for calculating the average price
  {
		if (units_sold)
      return revenue/units_sold; // return: devide revenue by the amount of units sold
  	else
  	 return 0;                   // else return nothing
  }

  std::string bookNo;      // for holding our book number/ISBN
  unsigned units_sold = 0; // for holding the amount of books sold
  double revenue = 0.0;    // for holding the price they were sold at
};


std::istream &read(std::istream &is, Sales_data &item) // funtion for getting input into a Sales_data object
{
  double price = 0;                              // for getting our price that the objects were sold at
  is >> item.bookNo >> item.units_sold >> price; // get input
  item.revenue = price * item.units_sold;        // calculate the revenue
  return is;
}

std::ostream &print(std::ostream &os, const Sales_data &item) // funtion for output
{
  os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price(); // print out values
  return os;        // return the output stream
}

Sales_data add(const Sales_data &lhs, const Sales_data &rhs) // for adding to Sales_data objects
{
  Sales_data sum = lhs; // sum for returning
  sum.combine(rhs);     // combine sum with rhs
  return sum;           // return the combined object
}

#endif // SALES_DATA_H


Main function

1
2
3
4
5
6
int main()
{
	Sales_data test1("0-01", 5, 4), test2("0-02"), test3(5, 45.00);

	return 0;
}


Output

1
1
2
1
3
No this is the expected behaviour.
closed account (EwCjE3v7)
Sorry forgot to say that, I`m confused by the way the first constructor is called before the delegated one.
Can someone please explain why?
The first one is the delegated one.
closed account (EwCjE3v7)
Wait what!!! No, I believe your info is incorrect. The other 2 are delegated functions.

As you can see the word delegated means

entrust (a task or responsibility) to another person, typically one who is less senior than oneself.


and the first one does it itself but the other two give control to the first one
2 and 3 are the delegating constructors. 1 is the delegated constructor.
closed account (EwCjE3v7)
Al right. But can you explain why 1 is called before 2 or/and 3 as those are the ones I used to call for variables 2 and 3
The C++ standard says that's how it should work.

§12.6.2/6
A mem-initializer-list can delegate to another constructor of the constructor’s class using any class-or-decltype that denotes the constructor’s class itself. If a mem-initializer-id designates the constructor’s class, it shall be the only mem-initializer; the constructor is a delegating constructor, and the constructor selected by the mem-initializer is the target constructor. The principal constructor is the first constructor invoked in the construction of an object (that is, not a target constructor for that object’s construction). The target constructor is selected by overload resolution. Once the target constructor returns, the body of the delegating constructor is executed. If a constructor delegates to itself directly or indirectly, the program is ill-formed; no diagnostic is required.

To me this way makes the most sense because constructors normally initialize all member variables of a class and you might want to reuse another constructor and then set some of the member variables to some other values in the body of the delegating constructor. This would not be possible if the delegating constructor ran first because the delegated constructor (called target constructor by the C++ standard) would overwrite all member variables.
closed account (EwCjE3v7)
Sorry Peter but I still do not get you

Should the following be done

First the delegating constructor should be called, and that called the delegated function then thats how it should be done not the other way around

EX
1
2
Class(int i, int i2) : a(i), b(i2) {} // This should be called second not first. 
Class(int i) : Class(i, 0) {} // if we were to initialize with this constructor, shouldnt this call the delegated function? 
No it's the other way around.

1
2
3
4
5
6
7
               First it calls the delegated constructor
               |
               v
Class(int i) : Class(i, 0) { }
                            ^
                            |
                            Secondly it runs the body of the delegating constructor
closed account (EwCjE3v7)
No, no no Peter. You do not get what I mean.

I know that but please tell me why this prints 1 and then 2.

1
2
3
4
Class(int i, int i2) : a(i), b(i2) {cout << "1" << endl;} // This should be called second not first. 
Class(int i) : Class(i, 0) {cout << "2" << endl;} // if we were to initialize with this constructor, shouldnt this call the delegated function?

Class i(10);

Why does this print 1 and then 2. Not the other way around. Shouldnt it call the delegating constructor first and then the delegated one.


EDIT

Oh lol, now I get it Thank you
Last edited on
Topic archived. No new replies allowed.