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