2

I have this code:

#include <iostream>
using namespace std;

class complex
{
    double re;
    double im;

public:
    complex(): re(0), im(0) {}
    complex(double x) {re = x, im = x;}
    complex(double x, double y) {re=x, im =y;}
    void print() {cout << re << " " << im;}
};

int main()
{
    complex c1;
    double i=2;
    c1 = i;
    c1.print();

    return 0;
}

My question is, why the code in this line compiles.

c1 = i;

The compiler gives no error(or warning), why?

Karen Baghdasaryan
  • 1,321
  • 4
  • 19
Joc380
  • 27
  • 5

4 Answers4

5

Let's examine what happens in the line.

c1 = i;

What happens is that operator= is called for class complex, which, in this case, is implicitly defined.

/////////////////////////////////////
//implicit copy assignment operator//
/////////////////////////////////////

complex& operator=(const complex& cmp)
{
    //the default implicit function of this operator is copying every member of cmp into this.
}

So it takes const complex& as argument, which can be bound to rvalue of type complex, then the compiler searches to see if there is a constructor accepting double parameter, so the expression is resolved into.

c1 = complex(i);

Which, obviously, can be executed.

Karen Baghdasaryan
  • 1,321
  • 4
  • 19
3

c1 = i invokes the constructor complex(double x) {re = x, im = x;}. If you'd prefer it didn't you can specify the constructor as explicit, like so:

explicit complex(double x) {re = x, im = x;}

Then the compiler would issue an error @ c1 = i;

KeyC0de
  • 4,177
  • 7
  • 40
  • 57
1

Because your constructor isn't explicit.

A constructor with a single non-default parameter (until C++11) that is declared without the function specifier explicit is called a converting constructor.

So having a constructor with a single non-default parameter, such as your complex(double x) will enable you to write complex s = 5.0 and call said constructor.

adnan_e
  • 1,619
  • 2
  • 15
  • 24
1

I have added some comments that explain how this program works. When you write c1 = i; then a temporary of type complex will be created using the converting constructor and then that temporary will be assigned to c1 using the assignment operator.

#include <iostream>

using namespace std;

class complex
{
   double re;
   double im;

   public:
       complex(): re(0), im(0){}
       //this converting constructor will be used to create a temporary of type complex from variable i
       complex(double x) 
       {
           std::cout<<"single parameter constructor used"<<std::endl;
           re = x;
           im = x;
           
       }
       complex(double x, double y) {re=x, im =y;}
       void print() {cout << re << " " << im;}
      
      //this assignment operator = will be used to assign the temporary(of type complex) created above to variable c1  
       complex& operator=(const complex &rhs)
       {
           std::cout<<"assignment operator used"<<std::endl;
       }
       complex(const complex&)
      {
          std::cout<<"copy constructor used"<<std::endl;
      }
};

int main()
{
    complex c1;
    double i=2;
    c1 = i;//first a temporary of type complex will be created using the converting constructor and then that temporary will be assigned to c1 using the assignment operator=
    c1.print();

    return 0;
}

If you want to prevent this kind of usage, you can make the converting constructor explicit by adding the keyword explicit in front of the converting constructor.

Anoop Rana
  • 19,715
  • 4
  • 12
  • 33