passing types to functions

I've got a game engine with a line-trace collision method which returns the first object it hits. I'd like to be able to pass it a class-type so that it can ignore objects of other types.

consider this pseudo-code:

1
2
3
4
Entity* TraceEntity( const Vec3f& LineStart, const Vec3f& LineEnd, const Type atype ) {
    // check collision on entities, ignore entities of type 'atype'.
    // return whatever it finds
}


I'd like to do this without template classes because it will result in a significant bloat in executable size every time I decided to trace for a new entity type (I've really developed a distaste for templates for this reason)

using type_info only checks for an object's deepest subclass, so it won't work for class C : public B : public A if I'm looking for classes of type B.

so, whats an elegant solution to this problem? I'm stumped for the time being...
Last edited on
If you have as a parameter const B*, and you pass it a C*, which inherits B and A, the object will be sliced, and only the B part will be visible.
One way is to create a virtual get_type function, which returns a chosen symbol for the type.
You could supply a character value for the 3rd argument if your classes have functions like these:
1
2
3
4
5
6
7
8
9
10
class A
{
    // access =  public or protected
    virtual char get_type(){ return 'A'; }
}
class A : public B
{
    virtual char get_type(){ return 'B'; }
}
// and so on... 

Then the test in your function would be like this:
1
2
3
4
5
6
7
Entity* TraceEntity( const Vec3f& LineStart, const Vec3f& LineEnd, char atype ) {    
    if( this->get_type() != aType )//  ignore entities of type 'atype'.
    {
        // check collision on entities,
        // return whatever it finds
    }
}
pograndy, one problem with that is a requirement to pass in an object. I'd have to create an object just to test with. could work, but it's yucky. temporaries can be quite big, especially in a game where a Player class, for example, has an extensive member list.

fun2code, that also will only match the deepest subclasses since get_type() is virtual, and without it beign virtual it wouldn't really work. I have a system for type checking quite like the one you proposed, and it involves storing the class hierarchy in a linked-list for every class I choose, and I can do very powerful type checking that even works with multiple inheritance... but, the problem is, it's slow. quite slow. as compared to typeid() and dynamic_cast ( although typeid() seems to be linear time as far as I've tested it)
Last edited on
> I have a system for type checking quite like the one you proposed,
> and it involves storing the class hierarchy in a linked-list for every class I choose,
> and I can do very powerful type checking that even works with multiple inheritance...

Why do you need to this linked list? Every class would have knowledge of what its base classes are.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <typeinfo>
#include <typeindex>
#include <vector>
#include <memory>
#include <iostream>

struct entity
{
    virtual ~entity() {}
    virtual bool is( const std::type_index& t ) const
    { return t == typeid(entity) ; }

    // ...
};

struct A : virtual entity
{
    virtual bool is( const std::type_index& t ) const override
    { return t == typeid(A) || entity::is(t) ; }

    // ...
};

struct B : virtual entity
{
    virtual bool is( const std::type_index& t ) const override
    { return t == typeid(B) || entity::is(t) ; }

    // ...
};

struct C : A
{
    virtual bool is( const std::type_index& t ) const override
    { return t == typeid(C) || A::is(t) ; }
};

struct D : B
{
    virtual bool is( const std::type_index& t ) const override
    { return t == typeid(D) || B::is(t) ; }
};

struct E : C, D
{
    virtual bool is( const std::type_index& t ) const override
    { return t == typeid(E) || C::is(t) || D::is(t) ; }
};

int main()
{
    std::vector< std::shared_ptr<entity> > seq =
    {
        std::make_shared<E>(),
        std::make_shared<A>(),
        std::make_shared<B>(),
        std::make_shared<entity>(),
        std::make_shared<C>(),
        std::make_shared<D>(),
        std::make_shared<A>(),
        std::make_shared<E>(),
        std::make_shared<C>(),
        std::make_shared<entity>(),
        std::make_shared<B>(),
        std::make_shared<E>(),
        std::make_shared<D>()
    };

    const std::vector< std::type_index > type_keys =
    { typeid(entity), typeid(A), typeid(B), typeid(C), typeid(D), typeid(E) } ;

    for( const auto& type : type_keys )
    {
        std::cout << "is of type " << type.name() << ": " ;
        for( std::size_t i = 0 ; i < seq.size() ; ++i )
             if( seq[i]->is(type) ) std::cout << i << ' ' ;
        std::cout << '\n' ;
    }
}



If a. you can afford the overhead of a dynamic_cast<>
and b. conversions from derived to base class is unambiguous
(base classes appearing more than once in the inheritance path are virtually inherited):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <vector>
#include <memory>
#include <iostream>

struct entity
{
    virtual ~entity() {}

    // ...
};

struct A : virtual entity
{
    // ...
};

struct B : virtual entity
{
    // ...
};

struct C : A
{
    // ..
};

struct D : B
{
    // ..
};

struct E : C, D
{
    // ...
};

template < typename T > inline bool is( const entity* e )
{ return dynamic_cast< const T* >(e) ; }

int main()
{
    std::vector< std::shared_ptr<entity> > seq =
    {
        std::make_shared<E>(),
        std::make_shared<A>(),
        std::make_shared<B>(),
        std::make_shared<entity>(),
        std::make_shared<C>(),
        std::make_shared<D>(),
        std::make_shared<A>(),
        std::make_shared<E>(),
        std::make_shared<C>(),
        std::make_shared<entity>(),
        std::make_shared<B>(),
        std::make_shared<E>(),
        std::make_shared<D>()
    };

    std::cout << "is of type C: " ;
    for( std::size_t i = 0 ; i < seq.size() ; ++i )
        if( is<C>( seq[i].get() ) ) std::cout << i << ' ' ;
    std::cout << '\n' ;
}



Last edited on
...genius. thank you.
Topic archived. No new replies allowed.