1

I want to extend the std::string with some functionality, so I derive my String from it. In order to make code like String str = stdStr; work, I've tried to overload the assignment operator, but my code is not being called for some reason. How can I fix it?

#include <string>

class String
    :
        public std::string
{

    public:
        /*
        I do know that this constructor will solve the problem, but is it possible to use the operator?

        String ( const std::string& stdString )
        {

            ...

        }
        */

        String& operator= ( const std::string& stdString )
        {
            ...
            return *this;
        }

};

int main()
{

    std::string foo = "foo";
    String bar = foo;

    return 1;

}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Kolyunya
  • 5,973
  • 7
  • 46
  • 81
  • 2
    Are you sure inheritance is the right way to extend? – Casper Beyer Apr 08 '13 at 10:49
  • 1
    I think extending string is a bad idea. It's impossible to tell what your new functionality is, but I can say with high confidence that inheritance is not the way to do it. – duffymo Apr 08 '13 at 10:51
  • The worst thing is that you call it `String` – UmNyobe Apr 08 '13 at 10:52
  • Extending the standard STL classes is generally considered a *very* bad idea. Naming that differs only in case is *another* thing that is considered such. – DevSolar Apr 08 '13 at 10:53
  • @UmNyobe it's in my personal namespace. What's the problem? – Kolyunya Apr 08 '13 at 10:54
  • To all: I'm just a beginner and I don't C++ in depth yet, I'm just trying to study... – Kolyunya Apr 08 '13 at 10:55
  • @Kolyunya: Then don't think about extending `std::string`. It's discouraged by *veterans*, so as a beginner you should take their word for it. First learn to work *in* the box, *then* learn how to *extend* the box without breaking it. – DevSolar Apr 08 '13 at 10:58
  • @DevSolar I should better do an `std::string` a member of my `String`, right? – Kolyunya Apr 08 '13 at 11:02
  • @Kolyunya: ...and call it "MyString" or "KolyunyaString" or somesuch. Yes, that would be better, unless you do your own implementation outright. Still, I think you should focus on other things. There is rather little that *can* be improved in `std::string` by a beginner. – DevSolar Apr 08 '13 at 11:18
  • @DevSolar I need a `splitByDelimiter` method for a string... So I need to extend basic string with such functionality. – Kolyunya Apr 08 '13 at 11:25
  • @Kolyunya: You fell for the (common) trap of not telling us your goal, but the problem you encountered halfway down the (wrong) road. You don't want to change how the string works, you want a function that works *on* strings - that shouldn't be in the string class, then. C++ style would be a function that takes iterators as parameters. Note that [`std::string::find()`](http://en.cppreference.com/w/cpp/string/basic_string/find) already exists, as does `find_first_of` or the more generic variants found in ``. If that is too low-level for you, simply write a convenience wrapper. – DevSolar Apr 08 '13 at 11:50
  • @DevSolar I previously had a `StringHelper` with a static function `split`. Is extending string (properly) worse than a static helper class? – Kolyunya Apr 08 '13 at 12:07
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/27767/discussion-between-devsolar-and-kolyunya) – DevSolar Apr 08 '13 at 12:25

7 Answers7

10
String bar = foo;

It's copy initialization (equivalently to

String bar(String(foo));

), not assignment. You should implement copy constructor for this works (or initialize variable by default and then assign foo to bar).

Anyway, it's bad idea to derive from standard C++ types, since these types has no virtual destructors. And composition is even better, than inheritance, in your example, you should use composition.

ForEveR
  • 55,233
  • 2
  • 119
  • 133
  • Thank you for an answer. Is it a better idea to make an `std::string` a member of my `String` and thus extend it's functionality? – Kolyunya Apr 08 '13 at 11:04
  • Yes, it is definitely better to make std::string a member of String. – riv Apr 08 '13 at 11:22
  • 1
    @Kolyunya: The fact that thre is no virtual dtor is a very weak argument. String are **VALUES**. They will never be allocated with `new` towards an `std::string*` and deleted as such. Properly used `string`-s and `String`-s will not suffer of any UB. `String`-s (as well as `string`, ar not OOP objects, so OOP rules must not apply here: instead VALUE arithmetic rules must apply) – Emilio Garavaglia Apr 08 '13 at 11:51
  • @riv: Have you ever tried? Is your boss paying you wile wasting your time rewriting all the 112 std::string prototypes? – Emilio Garavaglia Apr 08 '13 at 11:54
  • @EmilioGaravaglia `rewriting all the 112 std::string prototypes` the possible solution could be to make a `getStdString()` method in our `String` class and call those 112 functions on the member std string directly. – Kolyunya Apr 08 '13 at 12:04
  • @Kolyunya anyway, since in comments you tell, that you want only one function like `splitByDelimiter` - you shouln't create new class for this. This function should be free. – ForEveR Apr 08 '13 at 12:06
  • @Kolyunya: Yes, of course. But this way you get a class with a different interface, that will not work the same in eventual generic algorithms you may in future design to work on both. If this is a "problem" or not, depends on what and how you are planning to use your String class furthermore. If you are thinking to a specific class for a specific purpose, you're right. If you are thinking a class that can play a same role into a existent generic algorithm... well... that's not that trivial. What I'm pointing out, here, is that the "don't derive" advise is weak, without a context. – Emilio Garavaglia Apr 08 '13 at 12:17
9

The line String bar = foo it not an assignment, it is actually an equivalent to String bar(foo). If you write

String bar;
bar = foo;

your assignment operator will be called, as expected.

riv
  • 6,846
  • 2
  • 34
  • 63
6

The problem here is that your line

String bar = foo;

does not call the assignment operator, because you have no object to assign to (bar is not yet created); it calls a constructor. Indeed, it would call your commented-out constructor if it were available.

If you really want to use your operator, you have to write:

String bar;
bar = foo; // Now bar exists and you can assign to it

Incidentally, inheriting from std::string is not too good an idea because this class, as most other classes in the standard library, is not designed to be inherited from. Specifically, it lacks a virtual destructor, which would lead to trouble if you were using it polymorphically, such as:

std::string* str = new String();
delete str; // Oops; the wrong destructor will be called
Gorpik
  • 10,940
  • 4
  • 36
  • 56
  • 1
    Techically corred but... Can someone of the "don't derive" school affiliates tellmy for which f...ing reason one should use strings polymorphicaly? It's 30 year I'm programming and I've never seen a `std::string* str = new String();` in my old life from any string derived-class users. – Emilio Garavaglia Apr 08 '13 at 11:57
  • 2
    @EmilioGaravaglia: It's a matter of "distance to possible error". Deriving from a class that doesn't have a virtual destructor isn't an error in itself, but having such a class is getting your client *closer* to an error, because now you have to *document* that peculiarity of behaviour. And we all know how likely *that* is to happen. (Both the writing and the reading.) For beginners, you tend to give generic advice, and this time it's "don't extend standard classes". – DevSolar Apr 08 '13 at 12:48
  • @EmilioGaravaglia Adding to what DevSolar says, that line may be unlikely, but passing a `String*` to a function taking a `std::string*` is not. Passing references also takes you to polymorphic behaviour, though I admit that you wouldn't try to delete an object you received by reference. Of course, if you know the danger, you can take measures against it (for instance: enforce the use of `String` instead of `std::string` in your code), but the danger is still there. – Gorpik Apr 08 '13 at 15:19
  • @Gorpik: Can you show me a function (I mean a well known function) taking a `std::string*` ? I never seen one (and when I saw it was because the programmer was not aware of references: in other words, used C++ as an "ugly Java", or just used a pre-1996 C++) – Emilio Garavaglia Apr 08 '13 at 16:47
  • @DevSolar: there is **nothing** to document, here: both `std::string` and `String` don't have virtual dtors and hence **they both are not polymorphic**. If you know what it means, you know what to do (and not do). – Emilio Garavaglia Apr 08 '13 at 16:49
  • 1
    @EmilioGaravaglia: There's a slight difference between a class sans virtual destructor and a class *derived* from such a class, don't you think? And don't give me this "it's obvious if you know your stuff" talk. After well over a decade in the trade, I learned not to assume too much about the competence level of the next guy (or how he will be using a particular class). It's been quite a few occassions where I myself was tossed into an environment where I didn't know the language all that well and really enjoyed a thoughtful comment left by a considerate coder. – DevSolar Apr 09 '13 at 04:12
  • @DevSolar: No, I'dont't think. They are both just VALUE TYPES. In other word, you drop language features because you suspect others don't know how to use them. You did not convince me. You are in fact behaving like the ones that, to bash goto, duplicate code, introduce fake variables and the like. To me, you don't do certain things not because you know (by yor experience) what you gain or miss. – Emilio Garavaglia Apr 09 '13 at 10:15
  • 1
    @EmilioGaravaglia: Not interested in your flamebait, sorry. – DevSolar Apr 09 '13 at 10:42
1

In your case, despte = present, new String object will be created, thus requiring

String ( const std::string& stdString )  

to be uncommented. Another option would be to do something like

String bar;  
bar = foo;  

but that doesn't sounds like a good idea.

alexrider
  • 4,449
  • 1
  • 17
  • 27
1

Doing this uses the copy constructor:

String foo("foo");
String foo="hello";//assignment operator here

But this does not:

String foo;
String foo="hello";//copy constructor used here since foo was not initialized
Mppl
  • 941
  • 10
  • 18
1

The other upvoted answers are well-informed.

In the interest of directly answering your question, you're trying to do this.

    String& operator= ( const std::string& stdString )
    {
        // Call the base implementation
        return std::string::operator= ( stdString );
    }
Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
1

std::string foo = "foo"; String bar = foo;

The operation you are trying in main is not going to call copy assignment operator.It is equivalent of calling copy constructor.

Its better to avoid inheriting std::string as it doesn't define virtual destructor.

shivakumar
  • 3,297
  • 19
  • 28