Operator Overloading - Can This Be Done?

This is a discussion on Operator Overloading - Can This Be Done? within the C++ Programming forums, part of the General Programming Boards category; I just had a go at overloading the + operator. It works, but I want it to do more if ...

  1. #1
    Dr Dipshi++ mike_g's Avatar
    Join Date
    Oct 2006
    Location
    On me hyperplane
    Posts
    1,218

    Operator Overloading - Can This Be Done?

    I just had a go at overloading the + operator. It works, but I want it to do more if possible. For example if i do this in my code:
    Code:
    String something("strings");
    something + " together";
    It concatenates the two, but if I do:
    Code:
    String something("strings");
    "I want to put " + something;
    It wont work. Is there any way I can get what side of the operator the constant char pointer is on and whack it on the string accordingly?
    Heres my function so far:
    Code:
    String &String::operator+(const char *add)
    {
    	char *origin = str_ptr;
    	size+=strlen(add);
    	str_ptr = new char[size];
    	char *src = origin;
    	char *dst = str_ptr;
    	while(*src) *dst=*src, src++, dst++; //Copy original
    	while(*add) *dst=*add, add++, dst++; //Copy string to add
    	++*dst='\0';
    	delete[] origin;
    	return *this;
    }

  2. #2
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,251
    You have to make the operator a global function instead of a member function. For instance:

    Code:
    my_string operator+(const char * left, const my_string &right);
    Overloaded member operators always take the class type as their first parameter and there's no way to change that.

    Depending on the class implementation, this global function might have to be declared a friend, but there's nothing wrong with that.

  3. #3
    Dr Dipshi++ mike_g's Avatar
    Join Date
    Oct 2006
    Location
    On me hyperplane
    Posts
    1,218
    Okay, thanks for the fast replies. I'll have a go at that.

  4. #4
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,251
    Quote Originally Posted by mike_g View Post
    Okay, thanks for the fast replies. I'll have a go at that.
    Here's what I'd do -- you have a String constructor that takes a char *, right?

    Code:
    String operator+(const char *left, const String &right)
    {
        return String(left) + right;
    }
    In other words, convert the left hand side to a String and then invoke the String:: operator+() to do the concatenation.
    Last edited by brewbuck; 09-19-2007 at 03:20 PM.

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by brewbuck View Post
    Here's what I'd do -- you have a String constructor that takes a char *, right?

    Code:
    String operator+(const char *left, const String &right)
    {
        return String(left) + right;
    }
    In other words, convert the left hand side to a String and then invoke the String:: operator+() to do the concatenation.
    Hmm, I thought if there is a constructor String::String(const char *s), then the compiler will automatically be able to create a String object from a char *, and thus be able to use the normal String::operator+(const String &right)

    [Of course, you may find that it is more efficient to append the string by not converting the char * into a string first, but that is optimisation rather than functionality].

    --
    Mats

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #6
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,048
    Double Mats!

    Hmm, I thought if there is a constructor String::String(const char *s), then the compiler will automatically be able to create a String object from a char *, and thus be able to use the normal String:perator+(const String &right)
    It seems that way.
    Code:
    #include <iostream>
    #include <string>
    
    int main() {
        std::string name = "John " + std::string("Doe");
        
        return 0;
    }
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  7. #7
    Registered User
    Join Date
    Jan 2005
    Posts
    7,340
    Your example could work by operator+ being overloaded for (const char*, const std::string&), so it doesn't actually prove anything one way or the other.

  8. #8
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,251
    Quote Originally Posted by matsp View Post
    Hmm, I thought if there is a constructor String::String(const char *s), then the compiler will automatically be able to create a String object from a char *, and thus be able to use the normal String:perator+(const String &right)
    No, the compiler won't do that. Think what would happen if there was some other class Blah which also had a method of type:

    Code:
    String operator+(const String &right);
    Now the compiler has to decide whether to convert the char * into a String or into a Blah. This cannot be decided, so the compiler doesn't support such operations.

  9. #9
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,251
    Quote Originally Posted by dwks View Post
    Double Mats!


    It seems that way.
    Your example works because the standard library has exactly the kind of overloaded global function we're talking about here.

  10. #10
    Registered User
    Join Date
    Jan 2005
    Posts
    7,340
    The compiler does convert the const char* to the String, but not when operator+ is a member function. So, you do only need one non-member operator+ if you have appropriate non-explicit copy constructors:
    Code:
    #include <iostream>
    
    class Test
    {
        int i_;
    public:
        Test(int i = 1) : i_(i) { }
        int get_i() const { return i_; }
    };
    
    Test operator+(const Test& lhs, const Test& rhs) { return Test(rhs.get_i() + lhs.get_i()); }
    
    int main()
    {
        Test t;
        Test s = 3 + t;
        std::cout << s.get_i() << '\n';
    }
    If there are two possibilities, then the compiler will pick the best one or complain that the call is ambiguous.

  11. #11
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,251
    Quote Originally Posted by Daved View Post
    The compiler does convert the const char* to the String, but not when operator+ is a member function.
    That's exactly the point. The conversion can happen if the type being converted to explicit in the argument list. But in the case of a member function, the type is only implicit and the compiler has no way of deciding which conversion is appropriate.

    A related issue comes up when you've got more than one type conversion operator in a class:

    Code:
    class A, B;
    
    class C
    {
    public:
        operator A(); // convert C to A
        operator B(); // convert C to B.
    };
    Now imagine you've got two overloads:

    Code:
    int foo(const A &);
    int foo(const B &);
    Then imagine you instantiate a C and try to pass it to foo(). There are two conversions available that would make this call possible: to type A, or type B. What should happen in this case is ambiguous and I can't remember what the standard says about it.

  12. #12
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Am I mistaken but do you want operator+ to modify the left side argument (confusing + with +=)?

    Code:
    int a = 1, b = 2;
    a + b;
    cout << a;
    Analogy with ints: what would you expect this program to print?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  13. #13
    Registered User
    Join Date
    Jan 2005
    Posts
    7,340
    Another side point is that often operator+ is implemented in terms of operator+=, so once you've established the proper function signatures, you can and should initialize a temporary String with the first operand and use += to concatenate the second, then return that temporary. Also make note of the fact that operator+ should not return a reference, although operator+= can.

  14. #14
    Dr Dipshi++ mike_g's Avatar
    Join Date
    Oct 2006
    Location
    On me hyperplane
    Posts
    1,218
    Okay I made some progress but its still not doing exactly what I wanted. I basically made the operators call some member functions. As in:
    Code:
    String operator+(String &left, char *right)
    {
    	left.Add(right);
    	return left;
    }
    String operator+(char *left, String &right)
    {
    	right.Insert(left, 0);
    	return right;
    }
    This works for: something + " together";
    Or: "Put " + something;
    But not: "Put " + something + " together";
    Why cant I do that?

    Also I'm starting to realise that I was kind of clueless as to what I was trying to achieve when I started out. The sort of thing i really wanted to do is be able write code in a similar way to a scripting language using my functions. As in:
    Code:
    int num=100;
    char string_bit[]="blergh";
    my_string = "Blah blah" + string_bit + "blah "+ num + " blah....";
    Any advice on how I can go about this? I dont have a dont know where to start at the moment.

    Cheers.

  15. #15
    Registered User
    Join Date
    Jan 2005
    Posts
    7,340
    You need to be const correct. Any member function that does not modify the internal data needs to be a const function, and any String reference parameter that isn't meant to change the String should be a reference to const. In this case, that means using const String& instead of just String&.

    That will break your code, but your code isn't quite right anyway. You don't want to change the operands when doing operator+. Look at anon's post (#12) and see if it makes sense.

    You should be making a temporary variable and then modifying and returning that temporary variable.


    >> my_string = "Blah blah" + string_bit + "blah ";
    To do that, you need to construct a String object out of some of the character arrays. Every other item between the +'s needs to be a String. Since string_bit is a character array, you need to make it a String by constructing one:
    Code:
     my_string = "Blah blah" + String(string_bit) + "blah ";
    >> my_string = "blah "+ num + " blah....";
    Since num is a number, this will be even harder. It rarely makes sense to add a number to a string, but if you wanted to do that you'd have to be able to convert the number to a String somehow, and then let your String's operator+ handle the rest.
    Last edited by Daved; 09-19-2007 at 05:10 PM.

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21