2

I'm making my own string class and I'd like to ensure that CString a = "Hello " + "World!"; works (i.e. does not give a compiler error such as: cannot add 2 pointers).

My string class automatically converts to char* when needed and thus writing printf(a) would not break the code.

Is there any way to replace the compiler behavior around characters ? (i.e. between inverted commas, "abc"). Or, alternatively, to change the behavior of the + operator to handle strings?

dardisco
  • 5,086
  • 2
  • 39
  • 54
Sanctus2099
  • 1,669
  • 5
  • 22
  • 40
  • 2
    Writing a good string class is really really hard. std::string is really very good. Implicit conversion to char* for example, looks like a great idea when you're writing printf(str);, but a terrible idea when you're writing printf("%s\n", str); which won't work unless you're very careful. MFC's CString manages to work like this, and the horrible dirty jumps it has to go through to do it are not worth the bother (and fail horribly if you do delete (char*)str). Unless you have a great reason not to (homework?) then I would recommend not writing your own string class and using std::string – Stewart May 16 '10 at 19:19
  • A great reason to write one's own string class is to learn... Of course, in production code, this is a mistake. – paercebal May 16 '10 at 19:22
  • There are better ways to learn. String class design is full of massive but subtle pitfalls that have been stumbled into time and time again - if your tutor does not point those out, all you do is memorize them and apply them everywhere. – Stewart May 16 '10 at 19:34
  • Everyone tells me what I do is a mistake but every time I proove wrong(sooner or later). I just don't like the use of std::string and preffer something more simple to use. I've been working all day on this class and it's turning out really nice. Another thing is that I really want some other methods that are not in std::string and thus deriving it is rather complicated( and from what I know it might be a non-derivable class) and writing global functions is something I avoid when methods should be methods. It's only for in-house development so that's why I think it's not a mistake. – Sanctus2099 May 16 '10 at 19:37
  • Trust me - i've written my own string class before, more than once, and it wasn't worth it. The language provides an excellent one which has been implemented by smart people who know a lot about library development. If you intend to maintain the code, writing your own string class is a waste of your time which you could be spending working on features. If there is something you can't do with std::string, consider asking it here as a question - it is probably possible, but you haven't seen how yet. Also, non-member functions (global makes it sound bad) have their place in C++. – Stewart May 17 '10 at 08:02
  • @Sanctus2099 : I confirm all what was written by Stewart, because I did exactly the same, more than once. And yes, in C++, non-member functions can be part of the interface of an oject in the same namespace, too. But then, as its for in-house dev, I guess it's Ok. IMHO, no matter the complexity, writting one's own string class (and dogfooding it) is a good self-learning exercise. – paercebal May 17 '10 at 13:05

2 Answers2

9

You can't do exactly that because you can only overload operators for class types, and a string literal does not have class type.

You can take advantage of the concatenation of string literals that takes place during preprocessing:

CString a = "Hello " "World!";

or you can create a CString temporary and append to it:

CString a = CString("Hello ") + "World!";

or you could have a CString constructor that takes more than one argument:

CString a("Hello ", "World!");
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • But you can do the temporary one already with std::string str(std::string("Hello") + "World");!!!! – Robben_Ford_Fan_boy May 16 '10 at 18:53
  • @David: Yes; and...? I'm not sure I see what you're getting at. – James McNellis May 16 '10 at 18:59
  • The OP can't possibly improve on std::string in any case, so the whole exercise is just for learning. There's no point in comparing his class to std::string. – Puppy May 16 '10 at 19:29
  • I can allready do CString a = CString("Hello")+" World"; but I was just looking to make it even simpler. It's not a necesity but more like a personal taste. I did know it was hard to do/impossible but I was just looking for some clarification. – Sanctus2099 May 16 '10 at 19:31
6

The right answer

No. You cannot overload operators for built-ins, such as pointers.

James McNellis already answered the question, so I won't elaborate.

A possible alternative...

(I use std::string because I have no info on your in-house string)

Using a typedef will add some sugar to your syntax:

typedef std::string S_ ;

int main(int argc, char* argv[])
{
   std::string s = S_("Hello") + S_(" World") ;

   std::cout << "s : " << s << std::endl ;

   return 0 ;
}

But then, I wouldn't pollute the global namespace with a two-characters symbol just for a little sugar... And as far as I know, the code is inefficient (two string objects created, plus one temporary, without guarantee the compiler will optimize it all away...)

For curiosity's sake...

As a curiosity, by wrapping the string into a thin class, you can "add" those two pointers.

First, let's create the wrapper :

class StringThinWrapper
{
   public :

      StringThinWrapper(const char * p) : m_p(p) {}
      operator const char * () const { return m_p ; }

   private :
      const char * const m_p ;
} ;

As you can see, it's both inlined, and will do nothing... Still, it's able to cast itself into a const char * pointer (this kind of hack is dangerous, so be sure it's what you want to do).

Then, for this wrapper, let's overload the addition operator :

inline std::string operator + (const StringThinWrapper & lhs, const StringThinWrapper & rhs)
{
   std::string s(lhs) ;
   s += rhs ;
   return s ;
}

And now, let's write a main function using the wrapper, typedefed for ease of use :

typedef StringThinWrapper S_ ;

int main(int argc, char* argv[])
{
   std::string s = S_("Hello") + S_(" World") ;

   std::cout << "s : " << s << std::endl ;

   return 0 ;
}

Which compiles and gives the following result :

s : Hello World

Disclaimer: I just wanted to play with the idea your question gave me, and share it with you. Don't apply this kind of code just because you can. Indeed, this code should be refined to cover all cases efficiently before even being used, and even then, a simple typedef std::string S_ ; would be better IMHO.

AFAIK, I wouldn't use it because I'm happy with the current STL API.

And what about C++0x ?

In C++0x, you'll be able to create your own literals. The code will be kinda like :

std::string operator "str"(const char * p)
{ 
    return std::string(p); 
}

And you'll use it so :

int main(int argc, char * argv[])
{
   std::string s = "Hello"str + " World"str ;

   std::cout << "s : " << s << std::endl ;

   return 0 ;
}

For more information, see the following SO question: What new capabilities do user-defined literals add to C++?.

Community
  • 1
  • 1
paercebal
  • 81,378
  • 38
  • 130
  • 159
  • I see your point but using _S("some string") is roughly just the same as writing CString("some string"). I was just looking for a way to eliminate that completly. I for one don't like STL and that's why I'm making my own little classes. I heard about C++0x but never got my hands on it yet. It's indeed a intresting approach the thing with "literal overloading"(I hope this is technically correct). Would it be possible to maybe replace the "" literal and thus make my code work? – Sanctus2099 May 16 '10 at 19:44
  • @Sanctus2099 : Of course it is the same, but the `S_` notation is 5 chars shorter, and thus, somewhat more pleasing to read ... Again, James McNellis had it right : One can't overload the operators for built-ins, so both James' and my answer are the nearest approximation you'll have for your desired behaviour. – paercebal May 16 '10 at 19:49
  • @sanctus - don't use _S. It's a reserved name. No, you won't be able to replace "" to make your code work in 0x. – Edward Strange May 16 '10 at 20:09