3

I've created simple string class with some extra functions - its mainly for learning purposes. Now i want to overload operator + to allow me add two or more char* to my string.

this is what i want to make:

tom::string TXT;
TXT="abcde" + "1234";
cout << TXT << endl;

and output have to be:

abcde1234

i want to add more than just const char* later like:

..
int NUM=34;
TXT="abcd"+NUM+"098";
cout << TXT << endl;

and output have to be:

abcd34098

ive already done similar thing with operator <<

TXT << "abcd" << ".......";

but i need it with + operator. another thing is (probably it will be sorted with + operator)

void testF(tom::string INP) {
 cout << INP << endl;
}

int NUM=123;
testF("abcd"+NUM+"efg");

with output:

abcd123efg

if i'm trying anything still ending with error:

error: invalid operands of types ‘const char [4]’ and ‘const char [3]’ to binary ‘operator+’

here is part of the tom::string class:

namespace tom {
    class string {
        private:
            unsigned int        _length;
            unsigned int        _search_pos;
            bool                _changed;
            bool                _indexed;
            char*               _buffer;
            unsigned int*       _indexes;
            unsigned int        _indexCount;
            char*               _emptyChar;
            unsigned int        _null;
            char*               _retBuffer[RET_BUFFERS];
            short unsigned int  _retBufferIndex;

            // ADD to string
            void _add (const char* txt) {
                _buffer=(char*) realloc(_buffer, sizeof(char)*(_length+strlen(txt)+1));
                memcpy(&_buffer[_length], txt, strlen(txt));
                _length=_length+strlen(txt);
                _buffer[_length]=static_cast<char>(0);
                _changed=true;
                free(_indexes);
                _changed=true;
                _indexCount=0;
                _indexed=false;
                _indexes = (unsigned int*) malloc (sizeof(unsigned int)*2);
            }


// .......

            // REPLACE Whole string
            string& _rvs(const char* txt) {
                free(_buffer);
                free(_indexes);
                _changed=true;
                _indexCount=0;
                _indexed=false;
                _indexes = (unsigned int*) malloc (sizeof(unsigned int)*2);
                _length=strlen(txt);
                _buffer = (char*) malloc (sizeof(char)*(_length+1));
                memcpy(_buffer, txt, _length);
                _buffer[_length]=static_cast<char>(0);
                return (*this);
            }


// .......
        public:
            // ----------------------------------------------
            // |                CONSTRUCTOR                 |
            // ----------------------------------------------
            string(const char* _init="") {
                _length=0;
                _indexCount=0;
                _changed=false;
                _indexed=false;
                _buffer = (char*) malloc (sizeof(char)*(strlen(_init)+1));
                memcpy(_buffer, _init, strlen(_init));
                _indexes = (unsigned int*) malloc (sizeof(unsigned int)*2);
                _emptyChar = (char*) malloc (sizeof(char));
                _buffer[strlen(_init)]=static_cast<char>(0);
                _emptyChar[0]=static_cast<char>(0);
                _null=(unsigned int)-1;
                _retBufferIndex=0;
                for (short unsigned int ii=0; ii<RET_BUFFERS; ii++) {
                    _retBuffer[ii] = (char*) malloc (sizeof(char));
                    _retBuffer[ii][0]=static_cast<char>(0);                 
                }
            }

            string(const tom::string& _init) {
                string((const char*)_init.c_str());
            }
            // ----------------------------------------------
            // |                 DESTRUCTOR                 |
            // ----------------------------------------------
            ~string() {
                free(_buffer);
                free(_indexes);
                free(_emptyChar);
                for (short unsigned int ii=0; ii<RET_BUFFERS; ii++) {
                    free(_retBuffer[ii]);
                }
            }


// .....
        string& operator = (string &ttxt) {
            const char* txt=ttxt.c_str();
            return (_rvs(txt));
        }

            string& operator = (const char* txt) {
                return (_rvs(txt));
            }

            string& operator = (int num) {
                char bf[32];
                sprintf (bf, "%d", num);
                const char* txt=bf;
                return (_rvs(txt));
            }

            string& operator << (const char* txt) {
                _add(txt);
                return(*this);
            }

            string& operator << (int num) {
                char bf[32];
                sprintf (bf, "%d", num);
                const char* txt=bf;
                _add(txt);
                return(*this);
            }

            operator const char*() {
                return (const char*)_buffer;
            }
// .....
    }
}
  • 2
    I would get out of the habit of prefix identifiers with underscore. You probably do not know the associated rules (so far none broken). If you must prefix member variables use 'm_' – Martin York Apr 03 '11 at 23:15
  • 1
    For the record, there's a world of disagreement in the literature over whether or not string types should have the `+` operator defined. On the one hand, it seems like an obvious thing. On the other hand, the `-` operator doesn't make sense; nor do unary `+` and `-`. `*` only makes sense if one operand is a positive integer. And so on... – Mike DeSimone Apr 03 '11 at 23:16
  • 2
    Your class contains RAW owned pointers. I don't see the rule of 3 being applied! In face your copy constructor is completely broken. – Martin York Apr 03 '11 at 23:17
  • @Martin: to be honest i have no idea what you talking about ;-( ...i'm novice in c++ and i'm learning just from examples –  Apr 03 '11 at 23:33
  • @Mike: i know there is function to join strings but it's much easier and it's look better (for me) to have for example debug("Variable 1:"+NUM+", indexed: "+_indexed); like to do it with printf or << ...maybe the long previous perl experience leaving marks on me (. instead of + in perl) ;-) –  Apr 03 '11 at 23:38
  • @tominko: Then to be blunt you are not ready to write your own string class. You need to find and learn the rule of 3. A string class is a good place to learn. But you need to scale back your string class and concentrate on the basics of just being able to create and copy objects of your strings. – Martin York Apr 03 '11 at 23:57
  • @Martin: now i know what you mean with 'rule of 3' ... you are right i have mess with that a little bit... i've solved my problem here but that doesn't mean i feel like winner - next step is to improve it and the goal is to have nice proper written string class. –  Apr 04 '11 at 00:05
  • @tominko: see http://stackoverflow.com/questions/255612/c-dynamically-allocating-an-array-of-objects/255744#255744 – Martin York Apr 04 '11 at 01:15
  • @Martin: after reading few articles about copy constructor and assignment constructor i see that i have all in the code. can you please give me some example based on my code whats wrong? as a copy constructor there is `string(const tom::string& _init)` and assignment constructor there is `string& operator = (string &ttxt)` constructor and destructor are there as well, i have no memory leaks and its working as expected, but if its something wrong there please show me where. thanx –  Apr 05 '11 at 20:44
  • @tominko: Your copy constructor is broken to start with: `int main() { tom::string x("plop");tom::string y(x); }` should blow up quite nicely (or if you are lucky just cause heap corruption). See the link I provided above for instructions on how to do it properly. – Martin York Apr 05 '11 at 22:11
  • @tominko: It is really hard for a class to manage more than one RAW pointer correctly. Your object should implement string logic or memory management logic (this is know as `separation of concerns`). You're class does both which in a design principle is bad but also makes it really easy for me to break it if I try. – Martin York Apr 05 '11 at 22:14
  • @tominko: If you want I will help make it better. But the code snippet above is not compilable. Post the full code for the class above and I can point out the real problems in a new post below. – Martin York Apr 05 '11 at 22:16
  • i'll be happy if you'll find a spare time to help - self learning is hard and i have nobody to show me whats wrong. i've uploaded all files to http://yyy.boxip.co.uk/cpp/ (because it will be loooooots of code to paste it here). i'll be happy if you can comment it for me - you can email it then to me or put the wrong parts here (hope it will not be all wrong) - my email: www.thomas.webb(at)gmail.com –  Apr 05 '11 at 23:05
  • @tminko: You need to put @Martin otherwise I don't get alerted to your posts. I can post to your website so I put my first comment here: http://cl1p.net/Martin/ I have to do some work now but I will post more later. – Martin York Apr 05 '11 at 23:54
  • @Martin: i forgot to put your name there, sorry... thanx for the comments, i'll check it later - too tired now - it's 2am here ;-) –  Apr 06 '11 at 01:09
  • @Martin: i've added something there... –  Apr 07 '11 at 06:41

3 Answers3

4

You can't overload operators for pointer types only. At least one of the involved types needs to be a user-defined type.

Xeo
  • 129,499
  • 52
  • 291
  • 397
2
tom::string TXT;
TXT="abcde" + "1234";
cout << TXT << endl;

"abcde" + "1234" is evaluated first - you cannot make it work like you want.

You can make e.g. this work though:

tom::string TXT;
TXT=tom::string("abcde") + 987 + "1234";
cout << TXT << endl;

That will require an operator+(int) and an operator+(char const *)

EDIT: Sample operator:

operator+ should return a new object - not modify the object it is called on.

class string {
  ...
  friend string operator+(string const & LHS, char const * RHS) {
    string s = LHS;
    s._add(RHS);
    return s;
  }
};
Erik
  • 88,732
  • 13
  • 198
  • 189
  • if the first is (for example) tom::string("xx") then all on the right will be added and only matter if i have defined that type? –  Apr 03 '11 at 23:06
  • As soon as the LHS in the expression is your string, associativity of operators will ensure that operator+(yourstring, whatever) is called for all successive additions. – Erik Apr 03 '11 at 23:09
  • i've added `string& operator + (const char* txt) { _add(txt); return(*this); }` but i'm getting malloc error ;-( –  Apr 03 '11 at 23:11
  • @tominko: `operator+` should create and return a new object. `operator+=` should modify `this` – Erik Apr 03 '11 at 23:12
  • @Erik: thanx for that - still getting malloc error but there is possibility that something in my class is not right ;-) –  Apr 03 '11 at 23:20
  • @tominko: Looks like you don't have `operator=(string const &)` - you need that. – Erik Apr 03 '11 at 23:22
  • @Erik: i probably need to find out more about 'const' ;-) ...added `string& operator = (string const &ttxt) { const char* txt=ttxt.c_str(); return (_rvs(txt)); }` but without luck ;-( –  Apr 03 '11 at 23:26
0

Thanx to Erik! ... sorted (working)

i've added to tom::string class:

friend string operator+(string const & LHS, char const * RHS) {
    string s;
    s=LHS;
    s._add(RHS);
    return s;
}

next one throwing malloc error - i have to check it, but the first working perfect!

friend string operator+(string const & LHS, char const * RHS) {
    string s=LHS;
    s._add(RHS);
    return s;
}

and the testing:

void test2 (tom::string ooo) {
    cout << ooo << endl;
}

test2(tom::string("abcde")+"AA"+"BB");

showing:

abcdeAABB

Thanx again!