0

I created the following code for educational purposes and encountered a scenario for which I expected an error to occur, but no error occurred. Here is the class,

#include <string.h> // strcpy_s and strcat_s, not available in "<string>" #include <string> #include <iostream> class String { char *p; int len; public: String() { len = 0; p = '\0'; }; ~String() { delete p; }; String(const char * s); String(const String & s); friend String operator+(const String& a, const String &); friend std::ostream& operator<<(std::ostream& os, String const& m); }; String::String(const char * s) { len = strlen(s); p = new char[len + 1]; strcpy_s(p, len + 1, s); } String operator+(const String & l, const String & r) { String temp; temp.len = l.len + r.len; int temp_buffer_size = temp.len + 1; temp.p = new char[temp_buffer_size]; strcpy_s(temp.p, temp_buffer_size, l.p); strcat_s(temp.p, temp_buffer_size, r.p); return temp; } std::ostream & operator<<(std::ostream & os, String const & m) { return os << m.p; } int main() { String right("right"); String out = "left " + right + " "; std::cout << out; return 0; } 

If I run this code, it works fine. However my confusion comes from String out = "left " + right + " ";. Why does this line work, why did it not create an error such as "Cannot add const char * with String"? I am guessing here that it implicitly creates a String object while passing "left" as the constructor, but I was hoping for more evidence for this.

4
  • You should make the code in the question a minimal reproducible example -- in this particular code, keeping only the #include and the main function is sufficient for the program to run. The other functions are unnecessary. Commented Feb 4, 2021 at 2:15
  • The compiler is allowed to try one conversion operation (over simplified) when trying to find a matching function to call. So in the partial expression "left " + right the function String operator+(const String & l, const String & r) is a match if "left" can be turned into String, which it can be via the constructor String(const char * s); Try making the single argument constructors of the String class explicit to get the error you expected. Commented Feb 4, 2021 at 2:20
  • Related but not the same: stackoverflow.com/questions/3592357/string-concatenation Commented Feb 4, 2021 at 2:21
  • The rules of the language (roughly speaking) allow a single conversion (calling a constructor that can accept a single argument) on one of the operands in an expression involving a single operand. Addition is left-right associative so, for String out = "left " + right + " ", the compiler first tries to evaluate "left " + right, which can be done by performing a single conversion on "left" i.e. doing operator+(String("left"), right). That operator+() returns a String, so we're left with operator+(...) + "right". The same logic then applies with doing a conversion on "right". Commented Feb 4, 2021 at 2:38

1 Answer 1

0

Why does this line work, why did it not create an error such as "Cannot add const char * with String"?

Because your String class has an implicit constructor from const char*. That allows the compiler to convert string literals to objects of type String implicitly, when needed.

So, when processing the "left " + right expression, the compiler searched for all matching operators+ candidates and selected the best viable overload. In this example, operator+(const String&, const String&) is the only operator that can handle right argument. Hence the behavior. More details can be found in "Overload resolution".

To disable such conversion you should've declared the constructor explicit:

explicit String(const char * s); 

then you'd get the error message.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.