My program needs to handle different kinds of "notes": NoteShort, NoteLong... Different kinds of notes should be displayed in the GUI in different ways. I defined a base class of these notes, called NoteBase.
I store these notes in XML; and I have a class which reads from the XML file and store notes' data in vector<NoteBase *> list. Then I found I cannot get their own types, because they are already converted to NoteBase *!
Though if(dynamic_cast<NoteLong *>(ptr) != NULL) {...} may works, it's really too ugly. Implementing functions take NoteShort * or NoteLong * as parameter don't work. So, any good way to deal with this problem?
UPDATE: Thank you guys for replying. I don't think it should happen neither -- but it did happened. I implemented it in another way, and it's now working. However, as far as I remember, I indeed declared the (pure) virtual function in NoteBase, but forgot to declare it again in headers of the deriving classes. I guess that's what caused the issue.
UPDATE 2 (IMPORTANT):
I found this quotation from C++ Primer, which may be helpful to others:
What is sometimes a bit more surprising is that the restriction on
converting from base to derived exists even when a base pointer or
reference is actually bound to a derived object:
Bulk_item bulk;
Item_base *itemP = &bulk; // ok: dynamic type is Bulk_item
Bulk_item *bulkP = itemP; // error: can't convert base to derived
The compiler has no way to know at compile time that a specific
conversion will actually be safe at run time. The compiler looks only
at the static types of the pointer or reference to determine whether a
conversion is legal. In those cases when we know that the conversion
from base to derived is safe, we can use a static_cast (Section
5.12.4, p. 183) to override the compiler. Alternatively, we could request a conversion that is checked at run time by using a
dynamic_cast, which is covered in Section 18.2.1 (p. 773).
There are two significant trains of thought and code here, so shortest first:
You may not need to cast back up. If all Notes provide a uniform action (say Chime), then you can simply have:
class INote
{
virtual void Chime() = 0;
};
...
for_each(INote * note in m_Notes)
{
note->Chime();
}
and each Note will Chime as it should, using internal information (duration and pitch, for example).
This is clean, simple, and requires minimal code. It does mean the types all have to provide and inherit from a particular known interface/class, however.
Now the longer and far more involved methods occur when you do need to know the type and cast back up to it. There are two major methods, and a variant (#2) which may be used or combined with #3:
This can be done in the compiler with RTTI (runtime type information), allowing it to safely dynamic_cast with good knowledge of what is allowed. This only works within a single compiler and perhaps single module (DLL/SO/etc), however. If your compiler supports it and there are no significant downsides of RTTI, it is by far the easiest and takes the least work on your end. It does not, however, allow the type to identify itself (although a typeof function may be available).
This is done as you have:
NewType * obj = dynamic_cast<NewType*>(obj_oldType);
To make it entirely independent, adding a virtual method to the base class/interface (for example, Uuid GetType() const;) allows the object to identify itself at any time. This has a benefit over the third (true-to-COM) method, and a disadvantage: it allows the user of the object to make intelligent and perhaps faster decisions on what to do, but requires a) they cast (which may necessitate and unsafe reinterpret_cast or C-style cast) and b) the type cannot do any internal conversion or checking.
ClassID id = obj->GetType();
if (id == ID_Note_Long)
NoteLong * note = (NoteLong*)obj;
...
The option which COM uses is to provide a method of the form RESULT /* success */ CastTo(const Uuid & type, void ** ppDestination);. This allows the type to a) check the safety of the cast internally, b) perform the cast internally at its own discretion (there are rules on what can be done) and c) provide an error if the cast is impossible or fails. However, it a) prevents the user form optimizing well and b) may require multiple calls to find a succesful type.
NoteLong * note = nullptr;
if (obj->GetAs(ID_Note_Long, ¬e))
...
Combining the latter two methods in some fashion (if a 00-00-00-0000 Uuid and nullptr destination are passed, fill the Uuid with the type's own Uuid, for example) may be the most optimal method of both identifying and safely converting types. Both the latter methods, and them combined, are compiler and API independent, and may even achieve language-independence with care (as COM does, in qualified manner).
ClassID id = ClassID::Null;
obj->GetAs(id, nullptr);
if (id == ID_Note_Long)
NoteLong * note;
obj->GetAs(ID_Note_Long, ¬e);
...
The latter two are particularly useful when the type is almost entirely unknown: the source library, compiler, and even language are not known ahead of time, the only available information is that a given interface is provided. Working with such little data and unable to use highly compiler-specific features such as RTTI, requiring the object to provide basic information about itself is necessary. The user can then ask the object to cast itself as needed, and the object is has full discretion as to how that's handled. This is typically used with heavily virtual classes or even interfaces (pure virtual), as that may be all the knowledge the user code may have.
This method is probably not useful for you, in your scope, but may be of interest and is certainly important as to how types can identify themselves and be cast back "up" from a base class or interface.
Use polymorphism to access different implementations for the each of the derived classes like in the followin example.
class NoteBase
{
public:
virtual std::string read() = 0;
};
class NoteLong : public NoteBase
{
public:
std::string read() override { return "note long"; }
};
class NoteShort : public NoteBase
{
public:
std::string read() override { return "note short"; }
};
int main()
{
std::vector< NoteBase* > notes;
for( int i=0; i<10; ++i )
{
if( i%2 )
notes.push_back(new NoteLong() );
else
notes.push_back( new NoteShort() );
}
std::vector< NoteBase* >::iterator it;
std::vector< NoteBase* >::iterator end = notes.end();
for( it=notes.begin(); it != end; ++it )
std::cout << (*it)->read() << std::endl;
return 0;
}
As others have pointed out, you should try to design the base-class in a way that lets you do all the stuff you require without casting. If that is not possible (that is, if you need information specific to the subclasses), you can either use casting like you have done, or you can use double-dispatch.
Related
I am trying to implement a C++ class which will wrap a value (among other things). This value may be one of a number of types (string, memory buffer, number, vector).
The easy way to implement this would be to do something like this
class A {
Type type;
// Only one of these will be valid data; which one will be indicated by `type` (an enum)
std::wstring wData{};
long dwData{};
MemoryBuffer lpData{};
std::vector<std::wstring> vData{};
};
This feels inelegant and like it wastes memory.
I also tried implementing this as a union, but it came with significant development overhead (defining custom destructors/move constructors/copy constructors), and even with all of those, there were still some errors I encountered.
I've also considered making A a base class and making a derived class for each possible value it can hold. This also feels like it isn't a great way to solve the problem.
My last approach would be to make each member an std::optional, but this still adds some overhead.
Which approach would be the best? Or is there another design that works better than any of these?
Use std::variant. It is typesafe, tested and exactly the right thing for a finite number of possible types.
It also gets rid of the type enum.
class A {
std::variant<std::wstring, long, MemoryBuffer, std::vector<std::wstring>> m_data{}; // default initializes the wstring.
public
template<class T>
void set_data(T&& data) {
m_data = std::forward<T>(data);
}
int get_index() { // returns index of type.
m_data.index();
}
long& get_ldata() {
return std::get<long>(m_data); // throws if long is not the active type
}
// and the others, or
template<class T>
T& get_data() { // by type
return std::get<T>(m_data);
}
template<int N>
auto get_data() { // by index
return std::get<N>(m_data);
}
};
// using:
A a;
a.index() == 0; // true
a.set_data(42);
a.index() == 1; // true
auto l = a.get<long>(); // l is now of type long, has value 42
a.get<long>() = 1;
l = a.get<1>();
PS: This example does not even include the coolest (in my opinion) feature of std::variant: std::visit I am not sure what you want to do with your class, so I cannot create a meaningful example. If you let me know, I will think about it.
You basically want QVariant without the rest of Qt, then :)?
As others have mentioned, you could use std::variant and put using MyVariant = std::variant<t1, t2, ...> in some common header, and then use it everywhere it's called for. This isn't as inelegant as you may think - the specific types to be passed around are only provided in one place. It is the only way to do it without building a metatype machinery that can encapsulate operations on any type of an object.
That's where boost::any comes in: it does precisely that. It wraps concepts, and thus supports any object that implements these concepts. What concepts are required depends on you, but in general you'd want to choose enough of them to make the type usable and useful, yet not too many so as to exclude some types prematurely. It's probably the way to go, you'd have: using MyVariant = any<construct, _a>; then (where construct is a contract list, an example of which is as an example in the documentation, and _a is a type placeholder from boost::type_erasure.
The fundamental difference between std::variant and boost::any is that variant is parametrized on concrete types, whereas any is parametrized on contracts that the types are bound to. Then, any will happily store an arbitrary type that fulfills all of those contracts. The "central location" where you define an alias for the variant type will constantly grow with variant, as you need to encapsulate more type. With any, the central location will be mostly static, and would change rarely, since changing the contract requirements is likely to require fixes/adaptations to the carried types as well as points of use.
I'm not sure if this is a thing (to be honest I want to say that it is not), but I was wondering if there is a way to write a c++ function so that it can choose which type of object to return.
For example, I have a base class (A) that has 3 child classes (Aa, Ab, Ac). In a factory(F) class I have a std::map<UINT, A*> that holds a number of the child classes based on a UINT id. My goal is to write a function that can build and return the correct object when I pass in an id value.
I'll probably end up returning pointers and cloning the data that they point to, but I was just curious as to whether or not the aforementioned was actually possible.
Thanks!
C++ being statically typed, the return type of a function must be known at compile time. From here arises the question:
do I know the expected return type statically on each call site of F (== it only depends on constant expression values)
or does it depend on some runtime variable.
For case #1, a function template for F would be a good approach.
But in your case, it seems you are facing #2 (because you want to return a type depending on ID that we can assume is not a constant expression).
Because of the static typing, if you are to write a function (assuming you do not overload it, because it seems your input parameters are always the same), it will have a single and well-defined return type. Basically, you do not have a syntax to say that your factory F will return either an Aa Ab or Ac (and that is a very good thing, with regard to static typing and all the compiler verifications it enables ; )
C++ solution: Type erasure
With that being said, you have a few approaches to type erasure, that will allow you to return an instance of a variant type hidden behind a common single type.
The obvious one is the pointer-to-derived to pointer-to-base conversion. It is particularly usefull if you plan to use the returned object mainly through its A interface (i.e., you will call the virtual functions defined on A).
A* F(ID aId)
This A* could point to any type deriving from A. From here, you could call every function defined on A public interface on the returned pointer. Of course, if you wanted to call an operation that is only available on a subclass, you would need to know what is the exact type on call site,and then cast the pointer to a pointer-to-derived before being able to call the operation.
A possible alternative, if you'd rather avoid dynamic memory, could be boost::variant. At the cost of having to explicitly list all the possible types the function could return.
boost::variant<Aa, Ab, Ac> F(ID aId);
You can take a look at the tutorial for a quick introduction to the syntax and features.
Sure, something like this:
class MyMapClass
{
public:
template< class ExactType > ExactType * getValue(UINT key)
{
return dynamic_cast<ExactType*>(_myMap.at(key));
}
BaseType * at(UINT key)
{
return _myMap.at(key);
}
private:
std::map<UINT, BaseType*> _myMap;
}
However, since you are storing the pointers to base types, you can as well return them as is, and rely on the caller to make a specific cast, if that goes well with your application's architecture.
Unfortunately, you can not do it fully automatically. Sooner or later you will have to determine the exact class that hides behind the base class pointer, and make a cast. With the template solution it is done "sooner":
MyDerivedType * value = myMapClassInstance.getValue<MyDerivedType>(1);
If you prefer to return the base pointer, it is done "later":
BaseType * value = myMapClassInstance.at(1);
MyDerivedType * exactValue = dynamic_cast<MyDerivedType*>(value);
Function1 can be called with any type T which will be converted to (void*) to be able to add to the list but with this I lose the original pointer type (I need t store tham in one linkedlist because I cannot create one for every possible type). So somehow I need to save the type of the pointer as well. I know that it cant be done using c++. Can anyone suggest an alternative solution?
class MyClass
{
template<class T>
void function1(T* arg1)
{
myList.add((void*)arg);
}
void function2()
{
for(int i = 0; i < myList.size(); i++)
{
myList.get(i);
//restore the original pointer type
}
}
STLinkedlist<void*> myList;
}
The usual way to handle these kinds of problems is by using a public interface, in C++ this is done through inheritance. This can be a drag, especially in constrained situations, where a full class/interface hierarchy would provide too much code/runtime overhead.
In comes Boost.Variant, which allows you to use the same object to store different types. If you need even more freedom, use Boost.Any. For a comparison, see e.g. here.
At the end of the day (or better: rather sooner than later), I'd try to do things differently so you don't have this problem. It may well be worth it in the end.
If you lost the type info by going void* it is just gone. You can not just restore it.
So you either must store extra information along with the pointer, then use branching code to cast it back, or rather drive design to avoid the loss.
Your case is pretty suspicious that you do not what you really want.
A more usual case is that you want a polymorphic collection. That doesn't store any kind of pointers but those belonging to the same hierarchy. Collection has Base* pointers, and you can use the objects through Base's interface, all calling the proper virtual function without programmer's interaction. And if you really need to cast to the original type you can do it via dynamic_cast safely. Or add some type info support in the base interface.
Function1 can be called with any type T which will be converted to (void*) to be able to add to the list but with this I lose the original pointer type (I need t store tham in one linkedlist because I cannot create one for every possible type).
You're having the XY problem. The solution is not to decay your pointers to void* and store type information.
You simply can create a type for every possible type - you create a template type. You need to define an abstract interface for your "type for every object", then define a template class implementing this interface, that is particularized by type. Finally, you create your custom-type instance on your type of pointer received and store them by base class pointer (where the base class is your interface definition).
All that said, you (normally) shouldn't need to implement this at all, because the functionality is already implemented in boost::any or boost::variant (you will have to choose one of them).
General
Take into consideration, that if you want to store different objects inside a std::vector<void *>, mostly likely your application has a bad design. In this case, I'd think, whether it is really necessary to do it (or how can it be done in another way), rather than searching for the solution, how to do it.
However, there are no fully evil things in C++ (nor in any other language), so if you are absolutely certain, that this is the only solution, here are three possible ways to solve your problem.
Option 1
If you store only pointers to simple types, store the original type along with the pointer by an enum value or simply a string.
enum DataType
{
intType,
floatType,
doubleType
};
std::vector<std::pair<void *, DataType>> myData;
Option 2
If you store mixed data (classes and simple types), wrap your data in some kind of class.
class BaseData
{
public:
virtual ~BaseData() { }
};
class IntData : public BaseData
{
public:
int myData;
};
std::vector<BaseData *> myData;
Later, you'll be able to check the type of your data using dynamic_cast.
Option 3
If you store only classes, store them simply as a pointer to their base class and dynamic_cast your way out.
You could use boost::any to store any type in your list instead of use void*. It's not exactly what you want but I don't think you can restore the type in run time (as Kerrek said, it's not Java).
class MyClass
{
template<class T>
void function1(T arg1)
{
myList.add(arg);
}
template<class T>
T get(int i)
{
return boost::any_cast<T>(myList.get(i));
}
STLinkedlist<boost::any> myList;
};
This is my code:
class Base { /* something */ };
class Derived : public Base { /* something */ };
vector<Base*> v; // somebody else initializes it, somewhere
int counter = 0;
for (vector<Base*>::iterator i=v.begin(); i!=v.end(); ++i) {
if (typeof(*i) == "Derived") { // this line is NOT correct
counter++;
}
}
cout << "Found " << counter << " derived classes";
One line in the code is NOT correct. How should I write it properly? Many thanks in advance!
The names of typeid are implementation-defined and you shouldn't make assumptions about them. However, you could compare two typeid's.
if typeid(**i) == typeid(Derived)
Generally it would be considered a bad design (but if the purpose is just to write a not very practical program to count instances of Derived, it's just fine).
Note that this also requires Base to have a vtable (virtual functions and/or destructor), because non-polymorphic types just don't have a dynamic type which typeid checks (that is, they would all be instances of Base as far as typeid is concerned).
If you don't have any virtual functions, then you'll need to emulate this yourself. For example, if you like string comparisons and don't mind the overhead, add a field to Base that each type will fill out in its constructor and compare those. Otherwise use a unique integral identifier for each subtype etc.
Use dynamic_cast:
if ( dynamic_cast <Derived*>( *i) ) {
counter++;
For this to work, you will need to give your base class at least one virtual function - it really needs a virtual destructor anyway.
You can either use typeid (include <typeinfo>):
if (typeid(**i) == typeid(Derived))
or you can use a dynamic cast:
if (dynamic_cast<Derived*>(*i) != 0)
but both codes should generally be avoided in favour of a virtual function that is called and that is overridden to perform the appropriate action for each type.
Take a look on typeid operator.
In general, it's considered a bad idea to use it.
I think typeof is only available in C#.
The SO post "How to typeof in C++" may be of use ...
Update:
This may be of use:
The typeof operator, AFAIK, was a GCC
extension. It no longer works on
templated objects as of GCC 3.2.3.
Bug report:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=9459
Release changes:
http://www.gnu.org/software/gcc/gcc-3.2/changes.html
Currently GCC seems to have a really
hard time determining the type of
template functions even in legitimate
circumstances...
And I think GCC supports the __typeof__ operator.
And as others have stated, I guess you can use typeid as a replacement.
I think you want:
for (...) {
if (dynamic_cast<Derived*>(*i)) {
counter++;
}
}
dynamic_cast<> tries to convert the base class pointer to a derived-class pointer. If the object is of the derived type (or a subclass of it), the correct pointer is returned. If it is not that derived type it returns 'nil' to indicate that the conversion cannot be done successfully.
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.