Questions about constructors and operators

This is a discussion on Questions about constructors and operators within the C++ Programming forums, part of the General Programming Boards category; I decided to start an extremely simple experiment to revise on things I already know, but came across two things ...

  1. #1
    Always learning
    Join Date
    Apr 2009
    Posts
    25

    Questions about constructors and operators

    I decided to start an extremely simple experiment to revise on things I already know, but came across two things that puzzled me. I have a class named Number, which only holds an integer named "value":
    Code:
    class Number
    {
        public:
            Number(const int vl=0);
            void set_value(const int value);
            int get_value() const;
            Number operator+(const Number &n) const;
            Number operator-(const Number &n) const;
            Number operator-() const;
            Number &operator++();
            Number operator++(int);
            Number &operator=(const int n);
        private:
            int value;
    };
    
    ostream &operator<<(ostream &sout, const Number &n);
    istream &operator>>(istream &sin, Number &n);
    There is this thing that I can't understand. If I don't implement Number &operator=(const int n);, here is what happens:
    Code:
    Number n = 123; //constructor is called... I didn't know it would, but it makes sense
    Number j=n; //Default copy constructor
    j=n; //What??? The constructor is called!!!
    I know I can forbid lines 1 & 3 by using the keyword explicit before the constructor's prototype, but that's not my point at all. I want to know why would a constructor be called twice for the same instance. I'd think this would be a syntax error. What does the standard say about this?

    Here is the code for the constructor:
    Code:
    Number::Number(const int vl)
    {
        value = vl;
        cout << "Constructor!" << endl; //to know when the constructor is called
    }
    Another issue: If I remove the keyword const from ostream &operator<<(ostream &sout, const Number &n), this is what happens:
    Code:
    cout << ++n << endl; //works ok
    cout << n++ << endl; //syntax error!
    cout << n << endl;
    The error is: operators.cpp|41|error: no match for 'operator<<' in 'std::cout << (&n)->Number: operator++(0)'|

    This applies for all functions that return Number instead of Number&, but I don't understand why. What if I didn't want n to be const? I can't think of a reason I'd want that right now, but I want to understand why things are working this way.

    In case you are wondering, the reason I make trivial experiences like this is to understand the little details that I can't find in any book. This way I can understand how things really work, and prevent or fix potential bugs that will appear to me in the future.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,941
    Quote Originally Posted by Mr.Pointer
    I know I can forbid lines 1 & 3 by using the keyword explicit before the constructor's prototype, but that's not my point at all. I want to know why would a constructor be called twice for the same instance. I'd think this would be a syntax error. What does the standard say about this?
    I cannot duplicate your problem, so I have no idea why a constructor (other than the copy constructor) would be invoked when the copy assignment operator should be invoked. Maybe you are just misinterpreting your output.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Always learning
    Join Date
    Apr 2009
    Posts
    25
    Like I said, this happens when I remove the copy assignment operator, and when the class doesn't have an assignment operator for an int, it calls the constructor.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,941
    Quote Originally Posted by Mr.Pointer
    when the class doesn't have an assignment operator for an int
    That would explain the output if your example was:
    Code:
    Number n = 123;
    n = 456;
    since 456 would be converted to a Number and then the temporary Number would be assigned to n. However, your example is:
    Code:
    Number n = 123;
    Number j=n;
    j=n;
    in which case the constructor that optionally takes an int should not be invoked for j=n since both j and n are Number objects.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Code:
    Number n;
    int i;
    n = Number(i);
    That's where a Number object is implicitly constructed (unless you make the single-argument constructor explicit).
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  6. #6
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Just to clear up some things that the OP may have assumed incorrectly... There are 3 things that the compiler will generate automatically if you don't explicitly create them yourself: A default constructor, a copy constructor, and a copy assignment operator. i.e. these 3 functions:
    Code:
    Number()
    Number( const Number& )
    Number& operator=( const Number& )
    To prevent the compiler from creating those for you, just make them private and don't implement them.
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

  7. #7
    Registered User
    Join Date
    Jun 2005
    Posts
    6,439
    Quote Originally Posted by anon View Post
    Code:
    Number n;
    int i;
    n = Number(i);
    That's where a Number object is implicitly constructed (unless you make the single-argument constructor explicit).
    As a matter of fact, your example explicitly constructs an object.
    Right 98% of the time, and don't care about the other 3%.

  8. #8
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Sorry, my example was supposed to make it explicit where an implicit constructor call would happen in OP's code.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #9
    Always learning
    Join Date
    Apr 2009
    Posts
    25
    Whoops, I'm really sorry, I wrote a bad example! What I meant to write was something like this:
    Code:
    Number a = 20;
    a = 40;
    The constructor is indeed called twice, and your explanation makes a lot of sense.

    cpjust: It took me 3+ hours of debugging to learn that myself, in a different situation where I had a custom linked list. I had somehow missed that when I was studying my C++ ^^ but I'll never forget it now.

  10. #10
    Registered User
    Join Date
    Mar 2009
    Posts
    14
    Another issue: If I remove the keyword const from ostream &operator<<(ostream &sout, const Number &n), this is what happens:
    Code:

    Code:
    cout << ++n << endl; //works ok
    cout << n++ << endl; //syntax error!
    cout << n << endl;
    The error is: operators.cpp|41|error: no match for 'operator<<' in 'std::cout << (&n)->Number: operator++(0)'|

    This applies for all functions that return Number instead of Number&, but I don't understand why.
    The functions that return Number instead of Number& are returning temporary objects, and the compiler always makes temporary objects const. These const objects can't be used as non-const arguments. That's why you're getting the error.

    What if I didn't want n to be const? I can't think of a reason I'd want that right now, but I want to understand why things are working this way.
    n doesn't have to be const, as proven by your first line of code:
    Code:
    cout << ++n << endl; //works ok
    Specifying that an argument is const is the function's way of promising that it won't change the argument. A const argument can be filled by a const or a non-const object, while a non-const argument can only be filled by a non-const object (thus ruling out temporaries). Because of this, const arguments are the more general form, and should be used when possible.

  11. #11
    Always learning
    Join Date
    Apr 2009
    Posts
    25
    Quote Originally Posted by DirkMaas View Post
    the compiler always makes temporary objects const. These const objects can't be used as non-const arguments.
    So temporary objects are always const, which is something I didn't know. Thanks

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Mr.Pointer View Post
    So temporary objects are always const, which is something I didn't know. Thanks
    As such, they are not const. It's just that the compiler won't allow you to use one in a reference situation UNLESS it is a const reference.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. overloading operators
    By thracian in forum C++ Programming
    Replies: 12
    Last Post: 06-23-2008, 07:23 PM

Tags for this Thread


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21