-
June 22nd, 2009, 10:04 AM
#1
Constructor to extend existing class
I would like to extend the ANSI string class to include rudimentary split and join functions. I am NOT adding any new data fields to string:
class string_sj : public string {
public:
...
}
I would like to be able to use constructs such as
void arbitrary_function(string & s)
{
string_sj myString = s;
// or
string_sj *pMyString = new string_sj(s);
}
How do I add a constructor to class string_sj to allow this? I've tried
public:
string_sj(string & s) { string(s); }
and variation of this, but the compiler says: "redefinition of formal parameter 's' "
I have also tried
class string_sj : public string, string(string &) { ... }
but the compiler doesn't like that either.
I remember this topic being covered in the C++ class I took years ago, but I can't remember how to do it today.
K.
-
June 22nd, 2009, 10:12 AM
#2
Re: Constructor to extend existing class
That´s probably a bad idea since std::string´s destructor isn´t virtual and therefore std::string isn´t supposed to derive from.
Splitting/joining strings are operations that can be achieved by using std::string´s public interface, so why don´t you solve the task by implement non member functions?
- Guido
-
June 22nd, 2009, 10:29 AM
#3
Re: Constructor to extend existing class
Thanks for your suggestion on the specifics of extending string (and why it's a bad idea). I will consider your suggestion seriously.
On the more general problem of extending constructors, after doing some google searches, I found the following construct, which the compiler does accept:
class string_sj : public string {
public:
string_sj(string & s) : string(s) { }
...
};
This does ring a bell from what I learned (and forgot) in that class. I think this accomplishes what I intend (and is applicable to extending other classes where I'm only adding new methods).
K.
-
June 22nd, 2009, 10:39 AM
#4
Re: Constructor to extend existing class
Yes, you are looking at a constructor initialisation list, which can be used to initialise base class subobjects.
-
June 22nd, 2009, 12:40 PM
#5
Re: Constructor to extend existing class
Originally Posted by GNiewerth
That´s probably a bad idea since std::string´s destructor isn´t virtual and therefore std::string isn´t supposed to derive from.
This is something I hear over and over again, but I could never quite grasp what's so wrong about it. Yes, I understand why virtual destructors are necessary and why it's generally a bad idea to derive from a class with a non-virtual destructor, but:
- The only time not having a virtual destructor is relevant is when you try to delete a pointer to a base class which really points to a derived class object - in other words, when you're using the hierarchy polymorphically. Usually, including this time, the reason for deriving from std::string is to extend its functionality by adding member functions. I cannot conceive of a scenario where the resulting hierarchy would be used polymorphically - we generally don't even allocate string objects using new (other than implicitly, e.g. inside a vector<string>, but that's not a problem). Seriously, what design would possibly require something along the lines of a vector<string*> where some of the pointers point to std::string objects and some point to objects of the derived class?
- Even if we did attempt to use the hierarchy polymorphically, all that would happen is the destructor of the derived class would not be invoked. Is this a problem if the destructor of the derived class would be a no-op anyways (e.g. if no new data members were added to the derived class, only new methods)?
Old Unix programmers never die, they just mv to /dev/null
-
June 22nd, 2009, 12:44 PM
#6
Re: Constructor to extend existing class
Originally Posted by HighCommander4
I cannot conceive of a scenario where the resulting hierarchy would be used polymorphically
Indeed, so it would make more sense to either use composition or private inheritance, in which case this lack of a virtual destructor would no longer be a (potential) problem. (Of course, one can also use polymorphism without destroying derived class objects through base class pointers).
Originally Posted by HighCommander4
Even if we did attempt to use the hierarchy polymorphically, all that would happen is the destructor of the derived class would not be invoked. Is this a problem if the destructor of the derived class would be a no-op anyways (e.g. if no new data members were added to the derived class, only new methods)?
In practice, probably not. But strictly speaking, the behaviour is undefined, and in practice it is feasible for conditions to change under maintenance.
-
June 22nd, 2009, 03:02 PM
#7
Re: Constructor to extend existing class
Originally Posted by laserlight
Indeed, so it would make more sense to either use composition or private inheritance, in which case this lack of a virtual destructor would no longer be a (potential) problem.
If your objective is to extend the std::string class with a few methods of your own, then using composition or private inheritance would be counterproductive because you'd need to write wrappers for all the existing methods of std::string.
Old Unix programmers never die, they just mv to /dev/null
-
June 22nd, 2009, 03:14 PM
#8
Re: Constructor to extend existing class
Originally Posted by HighCommander4
If your objective is to extend the std::string class with a few methods of your own, then using composition or private inheritance would be counterproductive because you'd need to write wrappers for all the existing methods of std::string.
"If your objective is to extend the std::string class with a few methods of your own", then provide non-member functions that do that.
If you are going to add data members, then you are on your way to some specialised string class, so using composition or private inheritance and only forwarding (or using using declarations) relevant member functions makes sense.
-
June 22nd, 2009, 03:30 PM
#9
Re: Constructor to extend existing class
Originally Posted by laserlight
"If your objective is to extend the std::string class with a few methods of your own", then provide non-member functions that do that.
What if I want to avoid polluting a namespace with generic-looking function names like join() or trim() which may already be used for other things?
Old Unix programmers never die, they just mv to /dev/null
-
June 22nd, 2009, 03:32 PM
#10
Re: Constructor to extend existing class
Originally Posted by HighCommander4
What if I want to avoid polluting a namespace with generic-looking function names like join() or trim() which may already be used for other things?
Create another namespace.
-
June 22nd, 2009, 03:36 PM
#11
Re: Constructor to extend existing class
Originally Posted by laserlight
Create another namespace.
So now users of my string class, need to put not only but also
Code:
using my_namespace::join;
using my_namespace::trim;
at the top of their files - that's assuming they're not already using join() or trim() functions from other namespaces. If they are, they now need to qualify explicitly every invocation:
Code:
string s;
...
my_namespace::trim(s);
as compared to
Code:
better_string s;
...
s.trim();
Old Unix programmers never die, they just mv to /dev/null
-
June 22nd, 2009, 03:43 PM
#12
Re: Constructor to extend existing class
Originally Posted by HighCommander4
that's assuming they're not already using join() or trim() functions from other namespaces. If they are, they now need to qualify explicitly every invocation:
So? This is the very point of having namespaces in the first place: you can use using declarations and using directives where it is convenient, and fully qualify to disambiguate where necessary.
On a related note, you might want to read Sutter's article GotW #84: Monoliths "Unstrung" and an interview of Stroustrup where he discusses about Designing Simple Interfaces. Sutter's article references Meyers' article on How Non-Member Functions Improve Encapsulation.
EDIT:
Oh, and besides the choice of using declarations/directives and qualification with the given namespace name, the user can also alias the namespace name and use that to qualify the names in the namespace.
Last edited by laserlight; June 22nd, 2009 at 03:53 PM.
-
June 22nd, 2009, 10:34 PM
#13
Re: Constructor to extend existing class
A few things occurred to me as a read through this thread.
I've had a number of encounters with the notion that a derived class may not require a virtual destructor, and experiment does seem to confirm this viewpoint on a great many compilers. There are a number of tempting arguments to promote the reasoning, but there are complications.
Like so many other arguments of this kind, the merits and demerits of goto being an example in a current thread of discussion hear, it's long winded, but not quite as controversial. The matter is eventually settled, and laserlight has the point. Even though it appears to work, it is specifically 'marked' as undefined behavior, and that alone should be sufficient to deter it as a practice. There are more, though, perhaps more convincing. There's little way to guarantee the class we create on this assumption retains that assumption when the code changes hands, even our own future hands should we forget or skip the documentation "beyond this place there be dragons". Someone might add data to the class, forgetting that it may not be destroyed appropriately.
Another point, almost as convincing, is what happens when the proposed derived class would be used as a parameter to a function expecting a string, either of a string *, string & or string by value. It's not so much what happens to slice off the derived class (if it has no data, where' not loosing much), but what if the purpose will eventually be to get it back.
In other words, do we not expect to get a string FROM something which we would hope to treat or use as this derived string object? If true (and we know it could be under a wide variety of circumstances), how? Insisting on placing the functional extension in a derived class actually causes a problem at this point.
Moving the functionality into a set of non-member functions steps aside these issues, and they have the potential to benefit a lot more of our code than the perception of namespace complications.
Laserlight has some good references on these points - objects (that somewhat vaguely defined term) need not be defined only by member functions, but a family of functions acting upon a concept - wherever those functions are placed. In particular, the point that we may obtain a string object from sources outside OUR code for which we want these new features I think is the paramount issue; as non-member functions their use is more widely usable in a situation like this (extending an existing library).
But a composition approach need not be all that bad. The class could accept a string as a reference upon construction and when required provide an automatic conversion to string so it could still be used as a string when required. When you consider that the new behaviors are likely to be needed only on occasion, this is likely a comfortable solution.
Last edited by JVene; June 22nd, 2009 at 10:50 PM.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
-
June 23rd, 2009, 01:26 AM
#14
Re: Constructor to extend existing class
To bring this back full circle to the scenario that led to the original question...
Originally Posted by kahahn
I would like to extend the ANSI string class to include rudimentary split and join functions.
Consider using the Boost.StringAlgo library instead of writing your own functions.
-
June 23rd, 2009, 03:23 AM
#15
Re: Constructor to extend existing class
Adding 'useful' functionality to a class, whether by inheritance or composition always sounds like a great idea at first, but I know from experience that it can lead to bloated and inflexible classes.
My own experience came from creating a set of image classes many years ago; 8bit grey, 16bit grey, 8 bit RBG. Over the years, various coders added functionality to the various image classes (not always consistently), all of which were 'obviously' part of the image API. After a few years the classes had grown a large set of miscellaneous functions, not all implemented in each image class, not all useful in every application.
In the end we wiped the slate clean and started from an STL perspective and redesigned a set of templated classes and functions that separated images from algorithms.
Now the image classes are much easier to maintain (virtually nothing needs to be done to them now) and the algorithms are separate entities, only loosely coupled to the images (though iterators), and by way of templates, applicable to all image classes.
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|