I have a fairly simple class that looks like this:
class Person {
public:
Person(string name): _name(name) {};
void greet(const Person& person) const {
cout << "Hello, " << person._name << "!" << endl;
};
private:
string _name;
};
Note that the greet method takes a parameter of the Person type. When I pass it a Person object, it works as expected. Now let's pass it a string as a parameter in this way:
Person maher("maher");
maher.greet("sam");
When trying to run that code in QT (on a machine running ubuntu), it generates the following error:
no matching function for call to ‘Person::greet(const char [4])’
I was able to resolve this error by casting the string in this way: maher.greet(string("sam"));
My question is the following: Why can't c++ 'see' that I'm passing a string to the greet method? Does it have anything to do with the fact that the greet method accepts a Person object?
maher is a const char[6], and sam is a const char[4], and both decay to const char * implicitly, but none of them is actually a std::string.
In function calls, the C++ standard allows an implicit conversion to be performed if there's a non-explicit constructor of the target type that accepts the type of the actual value passed to the function.
This is what happens when you call the constructor: you pass a const char[6], which automatically decays to a const char *; the target type is std::string, which has a constructor that accepts a const char *; such constructor is called, and the Person constructor correctly receives his std::string parameter.
In the second case, this is not happening: Person does not have a constructor that accepts a const char *, but only a constructor that accepts a std::string. To reach the desired Person type the compiler would have to first convert the const char * to std::string, and then call the Person constructor. This double conversion is not allowed, mainly because overloading resolution would become a complete mess (which already is) with lots of ambiguous cases.
If you want to allow greet to be called with a C-style string you should either:
create a constructor for Person which accept a C-style string (const char *), so that it can be constructed directly from a const char *, without going through the prohibited extra conversion
create another overload for greet to accept an std::string.
On the other hand, IMO the cleaner alternative is just leave it as it is; the caller will just have to write
maher.greet(std::string("sam"));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With