CGedeus
CGedeus

Reputation: 11

C++ constructor with argument-list

I'm getting familiar with constructors in C++, and wondering why my C++ compiler can't find the constructor with an argument-list.

#include <cstdio>
#include <string>

const int defaultAge = 0;
const std::string unknown = "unknown";

class Patient {

    public:
     int age;
     std::string dob;
     std::string name;

    public:
     Patient();                                                           // Default Constructor
     Patient(int &years, std::string &birthdate, std::string &aliase);    // Argument-List Constructor
     void print();
};

Patient::Patient() : age(defaultAge), dob(unknown), name(unknown) {
    puts("Patient information from default consturctor:");
}

Patient::Patient(int &years, std::string &birthdate, std::string &aliase) 
: age(years), dob(birthdate), name(aliase) {
    puts("Patient information from copy consturctor:");
}

void Patient::print() {
    printf(" Name - %d\n DOB  - %s\n Name - %s\n", age, dob.c_str(), name.c_str());
}

int main(void) {

    Patient p0;
    p0.print();

    Patient p1(40, "August 11, 1980", "John Doe");
    p1.print();

    return 0;
}

I get the following error when attempting to compile the code:

compilation error

I'm using Apple clang version 11.0.0 as my compiler

Upvotes: 1

Views: 1600

Answers (2)

songyuanyao
songyuanyao

Reputation: 172964

You're declaring the parameters as lvalue reference to non-const, which can't be bound to rvalues like 40 (which is an int literal), "August 11, 1980" and "John Doe" (which are string literals and would be converted to std::string implicitly as temporories, which are rvalues).

You can make them lvalue reference to const (for both the declaration and definition), e.g.

Patient(const int &years, const std::string &birthdate, const std::string &aliase);
//      ^^^^^             ^^^^^                         ^^^^^

Or for int just make it pass-by-value.

Patient(int years, const std::string &birthdate, const std::string &aliase);
//      ^^^        ^^^^^                         ^^^^^

LIVE

Upvotes: 2

M.M
M.M

Reputation: 141628

songyuanyao points out the problem with your code. A good alternative is to pass by value and then move:

Patient::Patient(int &years, std::string birthdate, std::string aliase) 
    : age(years), dob(std::move(birthdate)), name(std::move(aliase))
{
    puts("Patient information from copy consturctor:");
}

In your original code (or songyuanyao's fix) then every string content is allocated twice , whereas in this version there is one allocation and one move .

As a rule of thumb, pass by value any time that the function is going to store a copy of the argument.

Upvotes: 1

Related Questions