Basically, I have a large project that uses a custom utility class c_string that inherits from std::basic_string<char>. For numerous reasons, I would like to edit this class so that
It does not derive from std::basic_string<char>
I do not have to re-implement all the functions
I do not have to touch every file that uses c_string
So I want to change from:
class c_string : public std::basic_string<char>
{
public:
typedef std::basic_string<char> Base;
c_string() : Base() {}
}
To:
class c_string
{
...
public:
...
c_string() {...}
}
So, I'm wondering if anyone has a good strategy for making this change with minimal impact.
If your class adds custom functionality (that your project needs) over std::string, then you're out of luck: you will either have to encapsulate std::string (and implement all methods to forward to std::string implementation) or inherit from std::string (inheriting from std::string is not a good idea in general).
If your class doesn't add extra functionality over std::string, then replace class c_string { ... } with typedef std::string c_string;.
There is another thing you can do and that is to change the public inheritance with private inheritance. Doing that, you will get a bunch of compile errors, because all of string's memberfunctions are now private to the clients of your class. You can then selectively make these public:
class my_string: std::string {
public:
typedef std::string base; // convenience
using base::const_iterator;
using base::begin;
using base::end;
};
You should understand private derivation not as "my_string is a std::string" but "my_string is implemented in terms of std::string". This technique avoids some of the downsides (implicit conversion, slicing etc) of deriving from a type that is not intended to be a baseclass, like std::string. Doing this conversion is easy, it's just work with little risk of breaking anything. Afterwards though, you have control over the forwarded interfaces, which makes conversion and refactoring much easier.
I can't see any way that you could avoid at least wrapping all the functions. The most straightforward way would be to have a private basic_string member, and just write wrappers that call the same function on that member.
I have nearly the same problem as zdp. Not inherit from std::string leads in a lot of code not to use methods (we have a lot like this) as void Foo(string &s_) where a string is the parameter in the function and the user puts a my_string to Foo(). In short therm: Inherit from std::string and you can send your my_string to any function which takes a my_string OR a std::string as parameter.
I would like to rewrite my my_string class but there are a lot of code with this problem in other hands and a lot of people have to change their code too.
One bad choice 14 years ago....... sh..
Related
I just miss some functions in the c++ standard library string class, so I just wanted to add these by myself. I wrote this:
#include <string>
class String : public std::string
{
public:
// some new fancy functions
};
and later noticed by reading some forums, that it is a bad idea to inherit from std::string and any other container from the standard library.
I just want the normal string, but with additional functions written by myself, how can I achieve this in the right way? Or is there no way to do it right and I have to right my own string class?
tl;dr: Use freestanding functions.
First of all - std::string is kind of a mess, and has too many methods as-is. It's bad design to lump functionality into a class which doesn't need to be in that class, and can easily be implemented using simpler, more basic class methods - as a freestanding function.
Moreover - std::string is at the same time unwieldy to manipulate (it's not a string buffer or an std::stringstream), and not impossible to manipulate, i.e. not immutable.
But coming back to my earlier point: The "right way" - if there is any - to do what you wanted is with freestanding functions. For example, suppose you want to randomly permute the contents of an std::string. Well, either:
std::string& jumble(std::string& str)
or
std::string jumble(std::string str)
or maybe, if you want to feel cool and micro-optimized,
std::string jumble(const std::string& str)
std::string jumble(std::string&& str)
depending if you want to use strings more as immutable or as mutable entities.
Also remember, that we don't really have a single std::string class - we have a template based on the character type (and an allocator etc.), so if you want to be generic, you have to accept this class:
template<
class CharT,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>
> class basic_string;
PS - If we had uniform call syntax, like Bjarne proposed - which we really should IMHO - your freestanding functions could simply be invoked as though they were members:
auto jumbled = my_string.jumble();
First of all, I know that the std::string class has all the functions I could possibly need. This is just for testing purposes to see what I'd be able to do in the future.
Anyway,
say I had this:
class MyString : public std::string { }
How would I then, for example, use:
MyString varName = "whatever";
because surely I'd get an error because "whatever" is a std::string not a member of the MyString class?
If you understand what I mean, how would I fix this?
(and by the way, I know this is probably a really silly question, but I am curious)
Deriving from a class simply to add member functions isn't a great idea; especially a non-polymorphic class like std::string. Instead, write non-member functions to do whatever you want with the existing string class.
If you really want to do this nonetheless, you can inherit the constructors:
class MyString : public std::string {
public:
using std::string::string;
};
Now you can initialise your class in any way that you can initialise std::string, including conversion from a character array as in your example. (By the way, "whatever" isn't a std::string, it's a zero-terminated character array, const char[9].)
I'm building an hierarchy of objects that wrap primitive types, e.g integers, booleans, floats etc, as well as container types like vectors, maps and sets. I'm trying to (be able to) build an arbitrary hierarchy of objects, and be able to set/get their values with ease. This hierarchy will be passed to another class (not mentioned here) and an interface will be created from this representation. This is the purpose of this hierarchy, to be able to create a GUI representation from these objects.To be more precise, i have something like this:
class ValObject
{
public:
virtual ~ValObject() {}
};
class Int : public ValObject
{
public:
Int(int v) : val(v) {}
void set_int(int v) { val = v);
int get_int() const { return val; }
private:
int val;
};
// other classes for floats, booleans, strings, etc
// ...
class Map : public ValObject {}
{
public:
void set_val_for_key(const string& key, ValObject* val);
ValObject* val_for_key(const string& key);
private:
map<string, ValObject*> keyvals;
};
// classes for other containers (vector and set) ...
The client, should be able to create and arbitrary hierarchy of objects, set and get their values with ease, and I, as a junior programmer, should learn how to correctly create the classes for something like this.
The main problem I'm facing is how to set/get the values through a pointer to the base class ValObject. At first, i thought i could just create lots of functions in the base class, like set_int, get_int, set_string, get_string, set_value_for_key, get_value_for_key, etc, and make them work only for the correct types. But then, i would have lots of cases where functions do nothing and just pollute my interface. My second thought was to create various proxy objects for setting and getting the various values, e.g
class ValObject
{
public:
virtual ~ValObject() {}
virtual IntProxy* create_int_proxy(); // <-- my proxy
};
class Int : public ValObject
{
public:
Int (int v) : val(v) {}
IntProxy* create_int_proxy() { return new IntProxy(&val); }
private:
int val;
};
class String : public ValObject
{
public:
String(const string& s) : val(s) {}
IntProxy* create_int_proxy() { return 0; }
private:
string val;
};
The client could then use this proxy to set and get the values of an Int through an ValObject:
ValObject *val = ... // some object
IntProxy *ipr = val->create_int_proxy();
assert(ipr); // we know that val is an Int (somehow)
ipr->set_val(17);
But with this design, i still have too many classes to declare and implement in the various subclasses. Is this the correct way to go ? Are there any alternatives ?
Thank you.
Take a look at boost::any and boost::variant for existing solutions. The closest to what you propose is boost::any, and the code is simple enough to read and understand even if you want to build your own solution for learning purposes --if you need the code, don't reinvent the wheel, use boost::any.
One of the beauties of C++ is that these kinds of intrusive solutions often aren't necessary, yet unfortunately we still see similar ones being implemented today. This is probably due to the prevalence of Java, .NET, and QT which follows these kinds of models where we have a general object base class which is inherited by almost everything.
By intrusive, what's meant is that the types being used have to be modified to work with the aggregate system (inheriting from a base object in this case). One of the problems with intrusive solutions (though sometimes appropriate) is that they require coupling these types with the system used to aggregate them: the types become dependent on the system. For PODs it is impossible to use intrusive solutions directly as we cannot change the interface of an int, e.g.: a wrapper becomes necessary. This is also true of types outside your control like the standard C++ library or boost. The result is that you end up spending a lot of time and effort manually creating wrappers to all kinds of things when such wrappers could have been easily generated in C++. It can also be very pessimistic on your code if the intrusive solution is uniformly applied even in cases where unnecessary and incurs a runtime/memory overhead.
With C++, a plethora of non-intrusive solutions are available at your fingertips, but this is especially true when we know that we can combine static polymorphism using templates with dynamic polymorphism using virtual functions. Basically we can generate these base object-derived wrappers with virtual functions on the fly only for the cases in which this solution is needed without pessimizing the cases where this isn't necessary.
As already suggested, boost::any is a great model for what you want to achieve. If you can use it directly, you should use it. If you can't (ex: if you are providing an SDK and cannot depend on third parties to have matching versions of boost), then look at the solution as a working example.
The basic idea of boost::any is to do something similar to what you are doing, only these wrappers are generated at compile-time. If you want to store an int in boost::any, the class will generate an int wrapper class which inherits from a base object that provides the virtual interface required to make any work at runtime.
The main problem I'm facing is how to
set/get the values through a pointer
to the base class ValObject. At first,
i thought i could just create lots of
functions in the base class, like
set_int, get_int, set_string,
get_string, set_value_for_key,
get_value_for_key, etc, and make them
work only for the correct types. But
then, i would have lots of cases where
functions do nothing and just pollute
my interface.
As you already correctly deduced, this would generally be an inferior design. One tell-tale sign of inheritance being used improperly is when you have a lot of base functions which are not applicable to your subclasses.
Consider the design of I/O streams. We don't have ostreams with functions like output_int, output_float, output_foo, etc. as being directly methods in ostream. Instead, we can overload operator<< to output any data type we want in a non-intrusive fashion. A similar solution can be achieved for your base type. Do you want to associate widgets with custom types (ex: custom property editor)? We can allow that:
shared_ptr<Widget> create_widget(const shared_ptr<int>& val);
shared_ptr<Widget> create_widget(const shared_ptr<float>& val);
shared_ptr<Widget> create_widget(const shared_ptr<Foo>& val);
// etc.
Do you want to serialize these objects? We can use a solution like I/O streams. If you are adapting your own solution like boost::any, it can expect such auxiliary functions to already be there with the type being stored (the virtual functions in the generated wrapper class can call create_widget(T), e.g.
If you cannot be this general, then provide some means of identifying the types being stored (a type ID, e.g.) and handle the getting/setting of various types appropriately in the client code based on this type ID. This way the client can see what's being stored and deal set/get values on it accordingly.
Anyway, it's up to you, but do consider a non-intrusive approach to this as it will generally be less problematic and a whole lot more flexible.
Use dynamic_cast to cast up the hierarchy. You don't need to provide an explicit interface for this - any reasonable C++ programmer can do that. If they can't do that, you could try enumerating the different types and creating an integral constant for each, which you can then provide a virtual function to return, and you can then static_cast up.
Finally, you could consider passing a function object, in double-dispatch style. This has a definite encapsulation advantage.
struct functor {
void operator()(Int& integral) {
...
}
void operator()(Bool& boo) {
...
}
};
template<typename Functor> void PerformOperationByFunctor(Functor func) {
if (Int* ptr = dynamic_cast<Int*>(this)) {
func(*ptr);
}
// Repeat
}
More finally, you should avoid creating types where they've basically been already covered. For example, there's little point providing a 64bit integral type and a 32bit integral type and ... it's just not worth the hassle. Same with double and float.
when doing
#include <string>
class MyString : public std::string
{
public:
MyString() {}
};
But the usage below:
MyString s = "Happy day";
MyString s("Happy Day");
MyString s = (MyString)"Happy day";
neither of them works.
It seems that there's something to do with constructors/operators declaration/overridding, but can anyone help point out where may I find these resources?
Thanks.
std::string isn't designed for inheritance. It doesn't have any virtual functions (not even the destructor!), so you can't override anything. It also doesn't have a protected interface, so you gain nothing from subclassing that you couldn't get by making some standalone utility functions that take std::string.
Keep in mind that most STL implementations expect you to use std::string with copy semantics, not reference semantics, and this makes the case for adding inherited fields or overriding functions even weaker.
If you really want something like std::string with extra functions, you could consider using composition instead of inheritance, but this isn't great either. You don't have to worry about the std::string destructor not getting called properly, but you do end up having to wrap a lot of methods from std::string that you need, which is tedious. Also, your utility functions will only work with MyString when most code is going to expect std::string, so it isn't very reusable.
You're better off making some utility functions that take std::string. Or, if std::string isn't providing what you need, you should go with some other string implementation that suits your needs. Here are some possibilities that come to mind:
SGI's STL extension, std::rope. It's in GNU C++, so maybe you can rely on it.
Boost has a pretty extensive string algorithm library that lets you use concepts to specify how your string is represented.
Also see this if you must "derive" from std::string
You need to define some constructors for the different types that you want to be able to convert into your strings. These constructors can basically just hand the parameters through to the underlying std::string.
If you don't manually create them, the compiler creates a default- and a copy-constructor for you:
MyString() : std::string() { }
MyString(const MyString &other) : std::string(other) { }
To allow construction from string literals, you need a constructor that takes a const char*:
MyString(const char* other) : std::string(other) { }
A constructor that takes a const std::string& would also be useful to convert std::strings to your string type. If you want to avoid implicit conversions of normal strings, you should make it explicit:
explicit MyString(const std::string &other) : std::string(other) { }
(Edited because my original version was full of errors and I can't delete the accepted answer)
The bottom line is that you shouldn't do this. The destructor on std::string isn't virtual. This means that if you do the following:
std::vector<std::string*> s_vector;
s_vector.push_back(new MyString("Hello"));
s_vector.push_back(new std::string("World"));
const std::vector<std::string*>::iterator s_vector_end = s_vector.end();
std::vector<std::string*>::iterator s = s_vector.begin();
for (; s != s_vector_end; ++s)
{
delete *s; // Error, MyString's destructor will
// not be called, but std::string's!
}
The only way this might be safe is if you don't add members to your string. You might think that you don't need any now, but someone who isn't aware of these issue may come along later (or you, when you've forgotten this advice perhaps) and add one, and then hey presto, you have a difficult to track down memory leak.
The problem is that you need to overload the constructor that takes const char* and call the base class constructor as follows:
class MyString : public std::string {
public:
MyString() {}
MyString( const char* c ) : std::string( c ) {}
};
All three of your tests should work then.
std::string isn't intended to be inherited from. It doesn't have any virtual methods so you can't override any of its methods.
You should look into composition. Or simply creating utility functions which operate on std::strings
You're defining a ctor MyString that takes no arguments. If overrides the other ctors, so there's no ctor taking a string argument at all.
You need to ctor of one argument of type const char *, something like
MyString(const char * s): std::string(s){}
(Don't trust the syntax, look it up; I don't write C++ every day any longer.)
Check the section in the C++ FAQ Lite on ctors.
(Oops. Const char *, not string. Told you I didn't write C++ every day.)
I have an interesting problem. Consider this class hierachy:
class Base
{
public:
virtual float GetMember( void ) const =0;
virtual void SetMember( float p ) =0;
};
class ConcreteFoo : public Base
{
public:
ConcreteFoo( "foo specific stuff here" );
virtual float GetMember( void ) const;
virtual void SetMember( float p );
// the problem
void foo_specific_method( "arbitrary parameters" );
};
Base* DynamicFactory::NewBase( std::string drawable_name );
// it would be used like this
Base* foo = dynamic_factory.NewBase("foo");
I've left out the DynamicFactory definition and how Builders are
registered with it. The Builder objects are associated with a name
and will allocate a concrete implementation of Base. The actual
implementation is a bit more complex with shared_ptr to handle memory
reclaimation, but they are not important to my problem.
ConcreteFoo has class specific method. But since the concrete instances
are create in the dynamic factory the concrete classes are not known or
accessible, they may only be declared in a source file. How can I
expose foo_specific_method to users of Base*?
I'm adding the solutions I've come up with as answers. I've named
them so you can easily reference them in your answers.
I'm not just looking for opinions on my original solutions, new ones
would be appreciated.
The cast would be faster than most other solutions, however:
in Base Class add:
void passthru( const string &concreteClassName, const string &functionname, vector<string*> args )
{
if( concreteClassName == className )
runPassThru( functionname, args );
}
private:
string className;
map<string, int> funcmap;
virtual void runPassThru( const string &functionname, vector<string*> args ) {}
in each derived class:
void runPassThru( const string &functionname, vector<string*> args )
{
switch( funcmap.get( functionname ))
{
case 1:
//verify args
// call function
break;
// etc..
}
}
// call in constructor
void registerFunctions()
{
funcmap.put( "functionName", id );
//etc.
}
The CrazyMetaType solution.
This solution is not well thought out. I was hoping someone might
have had experience with something similar. I saw this applied to the
problem of an unknown number of a known type. It was pretty slick. I
was thinking to apply it to an unkown number of unknown type***S***
The basic idea is the CrazyMetaType collects the parameters is type
safe way, then executing the concrete specific method.
class Base
{
...
virtual CrazyMetaType concrete_specific( int kind ) =0;
};
// used like this
foo->concrete_specific(foo_method_id) << "foo specific" << foo_specific;
My one worry with this solution is that CrazyMetaType is going to be
insanely complex to get this to work. I'm up to the task, but I
cannot count on future users to be up to be c++ experts just to add
one concrete specific method.
Add special functions to Base.
The simplest and most unacceptable solution is to add
foo_specific_method to Base. Then classes that don't
use it can just define it to be empty. This doesn't work because
users are allowed to registers their own Builders with the
dynamic_factory. The new classes may also have concrete class
specific methods.
In the spirit of this solution, is one slightly better. Add generic
functions to Base.
class Base
{
...
/// \return true if 'kind' supported
virtual bool concrete_specific( int kind, "foo specific parameters" );
};
The problem here is there maybe quite a few overloads of
concrete_specific for different parameter sets.
Just cast it.
When a foo specific method is needed, generally you know that the
Base* is actually a ConcreteFoo. So just ensure the definition of class
ConcreteFoo is accessible and:
ConcreteFoo* foo2 = dynamic_cast<ConcreteFoo*>(foo);
One of the reasons I don't like this solution is dynamic_casts are slow and
require RTTI.
The next step from this is to avoid dynamic_cast.
ConcreteFoo* foo_cast( Base* d )
{
if( d->id() == the_foo_id )
{
return static_cast<ConcreteFoo*>(d);
}
throw std::runtime_error("you're screwed");
}
This requires one more method in the Base class which is completely
acceptable, but it requires the id's be managed. That gets difficult
when users can register their own Builders with the dynamic factory.
I'm not too fond of any of the casting solutions as it requires the
user classes to be defined where the specialized methods are used.
But maybe I'm just being a scope nazi.
The cstdarg solution.
Bjarn Stroustrup said:
A well defined program needs at most few functions for which the
argument types are not completely specified. Overloaded functions and
functions using default arguments can be used to take care of type
checking in most cases when one would otherwise consider leaving
argument types unspecified. Only when both the number of arguments and
the type of arguments vary is the ellipsis necessary
class Base
{
...
/// \return true if 'kind' supported
virtual bool concrete_specific( int kind, ... ) =0;
};
The disadvantages here are:
almost no one knows how to use cstdarg correctly
it doesn't feel very c++-y
it's not typesafe.
Could you create other non-concrete subclasses of Base and then use multiple factory methods in DynamicFactory?
Your goal seems to be to subvert the point of subclassing. I'm really curious to know what you're doing that requires this approach.
If the concrete object has a class-specific method then it implies that you'd only be calling that method specifically when you're dealing with an instance of that class and not when you're dealing with the generic base class. Is this coming about b/c you're running a switch statement which is checking for object type?
I'd approach this from a different angle, using the "unacceptable" first solution but with no parameters, with the concrete objects having member variables that would store its state. Though i guess this would force you have a member associative array as part of the base class to avoid casting to set the state in the first place.
You might also want to try out the Decorator pattern.
You could do something akin to the CrazyMetaType or the cstdarg argument but simple and C++-ish. (Maybe this could be SaneMetaType.) Just define a base class for arguments to concrete_specific, and make people derive specific argument types from that. Something like
class ConcreteSpecificArgumentBase;
class Base
{
...
virtual void concrete_specific( ConcreteSpecificArgumentBase &argument ) =0;
};
Of course, you're going to need RTTI to sort things out inside each version of concrete_specific. But if ConcreteSpecificArgumentBase is well-designed, at least it will make calling concrete_specific fairly straightforward.
The weird part is that the users of your DynamicFactory receive a Base type, but needs to do specific stuff when it is a ConcreteFoo.
Maybe a factory should not be used.
Try to look at other dependency injection mechanisms like creating the ConcreteFoo yourself, pass a ConcreteFoo type pointer to those who need it, and a Base type pointer to the others.
The context seems to assume that the user will be working with your ConcreteType and know it is doing so.
In that case, it seems that you could have another method in your factory that returns ConcreteType*, if clients know they're dealing with concrete type and need to work at that level of abstraction.