Search code examples
c++oopconstructoroperator-overloadingassignment-operator

Do constructors do the same thing as the '=' operator?


  1. When we didn't define any = operator, how does the compiler know to use constructors?
  2. Isn't the constructor only called when defining a variable?
#include <string>

class Person
{
public:
    std::string name;
    Person(const char* fullName) : name(fullName) {}
};

int main()
{
    Person p1("Jibel Sadeghi"); // This is ok because we declared the constructor with a const char*
    /* When we didn't overload the '=' operator for 'const char*',
       how the next lines don't have any errors? */
    p1 = "Ben Sadeghi";
}

Solution

  • Isn't the constructor only called when defining a variable?

    No. A constructor is used when creating an object (instance of the class).

    That object may be held in a variable, or an element of an array, or dynamically allocated, or (in the case you have here) a temporary object.

    When we didn't define any = operator, how does the compiler know to use constructors?

    Your class has the default copy assignment operator, with signature

    Person& Person::operator=(const Person& assign_from);
    

    and default move assignment operator, with signature

    Person& Person::operator=(Person&& move_assign_from);
    

    When the compiler tries to compile

    p1 = "Ben Sadeghi";
    

    it sees that it needs Person::operator=(), looks at all the candidates (there's the default two, because you didn't provide any), and for each candidate it tries to convert the actual parameters to the types of the formal parameters.

    For copy assignment, the formal parameter has type const Person&, the actual parameter has type const char[12], and there's an implicit constructor able to perform the conversion. So Person::Person(const char*) can be called, followed by Person& Person::operator=(const Person&).

    For move assignment, the formal parameter has type Person&&, the actual parameter has type const char[12], and there's an implicit constructor able to perform the conversion. So Person::Person(const char*) can be called, followed by Person& Person::operator=(Person&&).

    The Person&& argument is a better match for the temporary person than const Person&, so in the end the sequence Person::Person(const char*) followed by Person& Person::operator=(Person&&) is chosen.