   Resolving Type From Abstract Property [c++]
  Hi there.After extensively searching the inet, ending up here, once again.I need to resolve the concrete type of a property class in order to display the value for viewing and editing in a gui.Consider the property class templated with an RTTI System.So my property class looks something like this:template< typename ValueType >class CProperty : public IProperty{...}class FloatProperty : CProperty<float>{}Now, the question is how to get the concrete type back in the best and most efficient way. This sounds like a job for dynamic_cast or MY_DYNAMIC_CAST for my rtti implementation. But is this the best way? #editSomething like this:IProperty* ptr = ...{CFloatProperty *p = MY_DYNAMIC_CAST( MY_TYPE::FLOAT, ptr ) ;if( p ) myPropertyWidget->display( p->GetVaule() ) ; // displays float}{CIntProperty *p = MY_DYNAMIC_CAST( MY_TYPE::INT, ptr ) ;if( p ) myPropertyWidget->display( p->GetVaule() ) ; // displays int}...#edit endExample would be:Imagine a PropertyWidget where I can pass an IProperty. But I need to resolve the real type in order to display the value for viewing it and probably editing it.Yes, one can do:class IProperty{ std::string toString()...}or something like this.For example:I have a CIntProperty as an IProperty passed to the property widget, and I want to display the int value within the CIntProperty object as a progress bar in my property widget. So here I can't get far with a toString method...Even worse.Imagine a class hierarchy like this:class A...class B : A...class C : B{ //put some properties here}Now, in my application, I pass A pointers around and I need to display the properties of the concrete object behind the A pointer.So, I would put all properties in a IProperty list, so I could do something like:class A{ // the base class from the preceeding code segment std::list<IProperty*>* GetProperties() ...}Is this a good idea?For example, at codeguru, there is a cpp property class, but its not considering this derivation problem. So, is the abstract property list a good idea or...? (As a second question)An idea to the first problem(resolving the type).I had the idea to put a visitor pattern into the property class. So every one how needes to do stuff with the concrete property class could just derive from the visitor and access the concrete type like this...Good or bad?ThankAlex#editVery basic quetsions... Sorry for that...   
  dynamic_cast will lead to O(n) visitation.A switch or the visitor design pattern will lead to O(1) visitation.   ;Quote:But is this the best way? There is no best - everything is a compromise.Quote:MY_DYNAMIC_CAST( MY_TYPE::INT, ptr ) ;Why macros?template < class T >Foo::getProperty(const char * name) {  IProperty * prop = ....  return dynamic_cast< CProperty<T>* >(prop);};...IntProperty * p = foo.getProperty<float>("health");Quote:template< typename ValueType >class CProperty : public IProperty{...}class FloatProperty : CProperty<float>{}Why such hierarchy? You only need 2 classes and typedefs:class IProperty {}template < class T >class TypedProperty : public IProperty {}typedef TypedProperty<float> FloatProperty;Quote:Is this a good idea?Returning raw pointers is rarely a good idea, and list for properties is probably the worst possible option for many reasons.struct Foo {  const std::vector< IProperty * > & getProperties() const { return properties; }  std::vector< IProperty * > props;};Quote:I had the idea to put a visitor pattern into the property class. So every one how needes to do stuff with the concrete property class could just derive from the visitor and access the concrete type like this...Good or bad?Again, there is no good or bad. Visitor is another option. Visitor can simplify things and it's much more suitable for non-polymorphic implementation. See container of boost::variants. Then you can also avoid the whole mess of dynamic allocations and polymorphism and just use value types (variant<int, float, std::string>).Quote:Imagine a PropertyWidget where I can pass an IProperty. But I need to resolve the real type in order to display the value for viewing it and probably editing it.For UI, and for editing and viewing, you definitely don't need to resolve the type.struct IProperty {  virtual void setFromString(const std::string & value) = 0;  virtual const std::string & getAsString() = 0;};;Quote:Original post by loufoqueA switch [...] will lead to O(1) visitation.Is there a new attribute in C++ that gives you the guarantee that a switch-statement will be translated into a table lookup + jump? Otherwise, your worst case is still O(n).;Quote:Is there a new attribute in C++ that gives you the guarantee that a switch-statement will be translated into a table lookup + jump? Otherwise, your worst case is still O(n).There is no need for such a guarantee for it to be O(1). Typically, it will generate branches when there are few cases, since that is faster, and still O(1) since the "few cases" is a constant.I don't feel like bothering searching whether this is mandated or not, but this is certainly the case of all implementations. Since it can be constant-time, a compiler would have to be stupid to generate sub-optimal code, especially since a lot of code relies on switch to be constant time to create finite state machines (parsers etc.)   ;  Hi.So you mean to use switch?!For example.My bounding volume classes are derived from IBoundingVolume like this:class IBoundingVolume{...}class CAabb : public IBoundingVolume{...}class CObb : public IBoundingVolume{...}In a massive collision detection simulation, you would use a switch?I did it with function pointers...@Antheus:Quote:IntProperty * p = foo.getProperty<float>("health");But here you must be sure that foo has a health property.If a class Foo is just derived from class Bar, you even must first figure out that foo is foo...I like the visitor pattern so I think this is the way to go and as you all said, its a good method.@Antheus:Quote:Why such hierarchy? You only need 2 classes and typedefs:Because of the RTTI System. I do RTTI myself, because dynamic_cast relies on the compilation with C++ RTTI typeid and stuff.Thanks   ;Quote:Original post by loufoqueQuote:Is there a new attribute in C++ that gives you the guarantee that a switch-statement will be translated into a table lookup + jump? Otherwise, your worst case is still O(n).Typically, it will generate branches when there are few cases, since that is faster,[...] Lol, so when there are many cases, no branches will be emitted at all? Surely, we have cmovs today, but do you think that whole applications will be emitted into a crazy bunch of cmovs, and run faster magically?Quote:[...]and still O(1) since the "few cases" is a constant.So if it takes between 1 and N branches to reach the correct jump target, it is said to be of O(1) complexity?Jokes aside. It has not much to do with the number of cases. It has to do with how good the jump target addresses can be saved in some kind of lookup table or some acceleration structure (though I don't know if modern compilers are capable of generating more than simple array lookups):Take this trivial example:#include <iostream>int main () { int in;   std::cin >> in;   switch (in) {   case 0: std::cout << "alpha\n"; break;   case 1<<9: std::cout << "bravo\n"; break; };}You see that there are only two targets.  Yet the compiler generates an ordinary "if-else"-alike:[...].section.rodata.LC0:.string"alpha\n".LC1:.string"bravo\n"[...]cmpl$0, -24(%ebp)je.L8cmpl$512, -24(%ebp)je.L9jmp.L7.L8:movl$.LC0, 4(%esp)movl$_ZSt4cout, (%esp)call_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKcjmp.L7.L9:movl$.LC1, 4(%esp)movl$_ZSt4cout, (%esp)call_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc.L7:[...]Even with -O3, gcc 4.3 gives me the following:[...]testl%eax, %eaxjne.L9movl$6, 8(%esp)movl$.LC0, 4(%esp)movl$_ZSt4cout, (%esp)call_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_i.L4:addl$36, %espxorl%eax, %eaxpopl%ecxpopl%ebpleal-4(%ecx), %espret.p2align 4,,7.p2align 3.L9:cmpl$512, %eaxjne.L4movl$6, 8(%esp)movl$.LC1, 4(%esp)movl$_ZSt4cout, (%esp)call_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_i[...]Quote:I don't feel like bothering searching whether this is mandated or not, [...]As I do. I just asked the compiler.;  So you want to say that a switch-case does not perform in O(1)...   ;Quote:Original post by directNoobSo you want to say that a switch-case does not perform in O(1)...It can, but not generally. Make sure that the possible values of the variable to query are near together, so ideally for each case X the next case is either case 1+X or the default case or the end of the switch statement.Btw, if you use an enum, and omit the default-case, most compilers will generate a nice warning about that you haven't written case-statements for all enum-values.edit: Following example added.#include <iostream>int main () {   enum Foo { alpha, bravo, charlie, delta, echo   };   int tmp;   std::cin >> tmp;   switch (static_cast<Foo> (tmp)) {   case alpha: std::cout << "alpha\n"; break;   case bravo: std::cout << "bravo\n"; break;   case charlie: std::cout << "charlie\n"; break;   case delta: std::cout << "delta\n"; break;   case echo: std::cout << "echo\n"; break;   };}[...]// comments added by mejmp*L8(,%eax,4).section .rdata,"dr".align 4L8:// Jump Table.longL3.longL4.longL5.longL6.longL7.textL4:movl$LC1, %eaxL10:movl%eax, 4(%esp)L9:movl$__ZSt4cout, (%esp)   // All calles to ostream&lt;< have been merged into a single call   // so all cases just push another string for the call, but don't call   // themselves.call__ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKcL2:leavexorl%eax, %eaxretL7:movl$LC4, %eaxjmpL10L3:movl$LC0, %eaxjmpL10L5:movl$LC2, %ecxmovl%ecx, 4(%esp)jmpL9L6:movl$LC3, %edxmovl%edx, 4(%esp)jmpL9[...] [Edited by - phresnel on April 28, 2009 2:35:41 AM];  I use enums, especially for my bounding volume classes. But there I built a jump-table( function pointer array ) which really gives me O(1).This is a direct mapping from enum value to array index...But this method is definitely not the most generic one.So what do you recommand I should use for my problem?ThanksAlex   