3
#include <iostream>

using namespace std;
class date{

    public:
        int month;
        int day;
        int year;

    private:
        date(int x, int y, int z);
    public:
        date(int x, int y);
};

date::date(int x, int y, int z): month{x}, day{y}, year{z} {

    cout << "Hello you called me PRIVATE constructor" << endl;

} 

date::date(int x, int y){
    cout << "Hello you called me PUBLIC constructor" << endl;
    date(x, y, 100);
}


int main(){

    date x{11, 21};

    cout << x.month << endl;
    cout << x.day << endl;
    cout << x.year << endl;

}

As you can see in above code i have two constructor and in main i create object x with two arguments.

This should call the public constructor which in turn calls the private constructor and initialises the public member month day and year.

But when i print members values out i don't get the desired results.

Hello you called me PUBLIC constructor
Hello you called me PRIVATE constructor
392622664
1
0

whereas the output should be:

Hello you called me PUBLIC constructor
Hello you called me PRIVATE constructor
11
21
100

I don't know where i did something wrong. Any help will be appreciated. Thank you.

Atul
  • 546
  • 4
  • 16
  • 5
    `date(x, y, 100);` Doesn't do what you think it does. It creates a new, temporary, `date`, that gets destroyed at the end of the statement. If you printed `this` in addition to the string, with `cout`, you would have noticed it. – Algirdas Preidžius Nov 29 '17 at 16:14

2 Answers2

8

Constructors have no names and can't be called. The expression date(x, y, 100); creates a temporary instance using the private constructor, which is immediately destroyed. You can delegate construction but you need to use proper constructor delegation syntax. To delegate a constructor, you must do so in the initialization list. It must be the only element in the initialization list. For example :

#include <iostream>

using namespace std;
class date {

public:
    int month;
    int day;
    int year;

private:
    date(int x, int y, int z);
public:
    date(int x, int y);
};

date::date(int x, int y, int z) : month{ x }, day{ y }, year{ z } {

    cout << "Hello you called me PRIVATE constructor" << endl;

}

date::date(int x, int y) : date(x, y, 100) {
    cout << "Hello you called me PUBLIC constructor" << endl;
}


int main() {

    date x{ 11, 21 };

    cout << x.month << endl;
    cout << x.day << endl;
    cout << x.year << endl;
}
François Andrieux
  • 28,148
  • 6
  • 56
  • 87
  • 1
    Note that output would be `"Hello you called me PRIVATE constructor"` followed by `"Hello you called me PUBLIC constructor"` (reversed order from expected output of OP). – Jarod42 Nov 29 '17 at 16:42
4

As the other answers state, constructors can't be called directly normally; however they can CAN be directly called from other constructors (in c++11 onwards), but the syntax is very specific.

date::date(int x, int y):
      date(x, y, 100)
{
    cout << "Hello you called me PUBLIC constructor" << endl;
}

ie they must be called as part of the initialiser list.

Note that this will call things in a different order than you have specified

UKMonkey
  • 6,941
  • 3
  • 21
  • 30
  • Why is it contrary to the comment? – Slava Nov 29 '17 at 16:18
  • @Slava because the comment was deleted – UKMonkey Nov 29 '17 at 16:19
  • @UKMonkey That was my comment. I deleted it because it was redundant with the other comment. Constructors cannot be called directly. They are nameless. Delegate construction is strictly speaking distinct from calling a constructors, thought that's what it looks like. – François Andrieux Nov 29 '17 at 16:19
  • @FrançoisAndrieux You could call placement new on this ... but I think I'm going to cry in a corner now – UKMonkey Nov 29 '17 at 16:22
  • @UKMonkey It seems like you could, but it's technically undefined behavior unless you also directly call the destructor first. But then I don't think you can even do that, since I don't believe you can call a destructor before the constructor has finished. – François Andrieux Nov 29 '17 at 16:24
  • Are you saying this wasn't valid until C++11? Before that you couldn't put another constructor of the same class in the initializer list? – Mark Ransom Nov 29 '17 at 16:25
  • 1
    @MarkRansom That's what I'm saying indeed. It's something which C++ picked up from other languages. This thread discusses it https://stackoverflow.com/questions/308276/can-i-call-a-constructor-from-another-constructor-do-constructor-chaining-in-c – UKMonkey Nov 29 '17 at 16:27