Thread: Operator Overloading - Can This Be Done?

Hybrid View

Previous Post Previous Post   Next Post Next Post
  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
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    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
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    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.

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    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.

  5. #5
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    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.

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    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.

  7. #7
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    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.

  8. #8
    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).

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    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.

  10. #10
    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.

  11. #11
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    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.

  12. #12
    Dr Dipshi++ mike_g's Avatar
    Join Date
    Oct 2006
    Location
    On me hyperplane
    Posts
    1,218
    I started out using constant chars, but then I kept getting grief from my compiler about converting const char* to char*, so i just made everything non constant. Anyway I think I'm going to scrap this as its not doing anything useful. But I would still like to know how I could add as many things as I wanted to a string like:

    my_string = "jfh" + number + "djfbjsd" + another_string;

    The equals operator comes last right? So where would I store the things as they are getting added together each step? I'd basically have to do that and then just set my_string to the result. Like I said, I got no idea how I could go about this.

    Cheers.

    [edit] Just read your edit daved. thanks, i'll see what I can come up with. [/edit]
    Last edited by mike_g; 09-19-2007 at 05:19 PM.

  13. #13
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    The const char* is less important than const String&, but you should put both there.

    You need your operator+ to work if you want to do anything like my_string = "jfh" + number + "djfbjsd" + another_string; and that means fixing your consts.

    The reason is that when you have a bunch of things added together like that, each addition is done one at a time. The first two pieces are added and stored in a temporary string, which is then added to the third piece and that result is stored in another temporary string, and that is then added with the fourth piece, and so on. A temporary object cannot be modified by the function, which is why the reference needs to be const.

    So to solve your problem, get your operator+(const String& left, const String& right) working, then strings like this "jfh" will work automatically. Adding numbers is more difficult like I mentioned in an edit above.

  14. #14
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> Any advice on how I can go about this?

    just an example using existing classes:

    Code:
    struct cat
    {
            cat(void)
            {   }
    
            template <typename Type>
            cat(Type const & rhs)
            {
                    std::stringstream ss;
                    ss << rhs;
                    buf = ss.str();
            }
    
            operator
            std::string & (void)
            {
                    return buf;
            }
    
            operator
            std::string const & (void) const
            {
                    return buf;
            }
    
            std::string buf;
    };
    
    cat
    operator + (cat const & lhs, cat const & rhs)
    {
            return lhs.buf + rhs.buf;
    }
    
    int 
    main(void)
    {
    	std::string msg = cat() + 1 + 2 + 3 + "..." + 'a' + 'b' + 'c';
    	std::cout << msg << std::endl;
    	return 0;
    }
    Last edited by Sebastiani; 09-20-2007 at 01:47 PM. Reason: formatting
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  15. #15
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    I suggest losing the old C throwback of (void), just use ().

    Afaik, there is no such thing of a templated constructor, so I expect that it would not work.

    Last of all, what's stopping the compiler from interpreting 1 + 2 + 3 as 6? (Note I'm not sure if it will or not, just asking)
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

Popular pages Recent additions subscribe to a feed