Template, dziedziczenie - reference is ambiguos

Odpowiedz Nowy wątek
2011-08-11 12:20
cppppppp
0

Witam.

Mam sobie template InstancesController, który posiada parę metod statycznych. Służy on do kontrolowania liczebności utworzonych instancji klasy.

template<class T>
class InstancesController
{
    public:
        InstancesController() ;
        virtual ~InstancesController() ;
 
        static const unsigned getNumberOfInstances() ;
        static const unsigned getNextIndex() ;
        static InstancesController<T> *getInstance(unsigned index) ;
        static void clear() ;
    private:
        static std::map<unsigned, InstancesController<T>*> instances ;
        static unsigned nextIndex ;
        const unsigned index ;
};

Mam też 2 testowe klasy:

    class A : public InstancesController<A>
    {
        public:
            A(){}
            virtual ~A(){}
    };
 
    class B : public InstancesController<B>, protected A
    {
        public:
            B(){}
            virtual ~B(){}
    };

gdy w testach chcę wywołać np. B::clear() dostaję:

test/suite/InstancesControllerTest.cpp: In member function ‘virtual void<unnamed>::InstancesController_DerivingTest_Test::TestBody()’:
test/suite/InstancesControllerTest.cpp:70: error: reference to ‘clear’ is ambiguous
src/tools/InstancesController.h:84: error: candidates are: static void InstancesController<T>::clear() [with T = InstancesControllerHelpers::A]
src/tools/InstancesController.h:84: error:                 static void InstancesController<T>::clear() [with T = InstancesControllerHelpers::B]

Właściwie czemu? Przecież B dziedziczy po A protected, więc z poziomu testu A::clear() nie powinno być widoczne...

Dzięki za wszelkie podpowiedzi

Pozostało 580 znaków

2011-08-11 12:36
0

a spróbuj:
InstancesController<B>::clear();


░█░█░█░█░█░█░█░█░█░█░█░
edytowany 3x, ostatnio: krwq, 2011-08-11 12:38

Pozostało 580 znaków

2011-08-11 12:40
cppppppp
0

no tak działa. ale właśnie chciałem zrobić to szybko poprzez dziedziczenie, aby odwoływać się przez B::clear() i nie musząc kopiować interfejsu w klasie B

Pozostało 580 znaków

2011-08-11 12:43
0

ale skoro B dziedziczy po A, to w instance managarze znajdą się również klasy bazowe B z klasy A, więc wystarczy że podziedziczysz po A, a następnie wywołasz sobie składową wirtualną


░█░█░█░█░█░█░█░█░█░█░█░

Pozostało 580 znaków

2011-08-11 12:43
cppppppp
0

dobra, sam doszedłem. zrobiłem tak:

template<class T>
class InstancesController : public T
{
    public:
        InstancesController() ;
        virtual ~InstancesController() ;
 
        static const unsigned getNumberOfInstances() ;
        static const unsigned getNextIndex() ;
        static InstancesController<T> *getInstance(unsigned index) ;
        static void clear() ;
    private:
        static std::map<unsigned, InstancesController<T>*> instances ;
        static unsigned nextIndex ;
        const unsigned index ;
};

klasy:

    class A_
    {
        public:
            A_(){}
            virtual ~A_(){}
    };
    typedef InstancesController<A_> A ;
 
    class B_ : public A
    {
        public:
            B_(){}
            virtual ~B_(){}
    };
    typedef InstancesController<B_> B ;
 
    class C_ : public A
    {
        public:
            C_(){}
            virtual ~C_(){}
    };
    typedef InstancesController<C_> C ;
 
    class D_ : public B, public C
    {
        public:
            D_(){}
            virtual ~D_(){}
    };
    typedef InstancesController<D_> D ;

każda z operacji:

        A::clear() ;
        B::clear() ;
        C::clear() ;
        D::clear() ;

działa

Pozostało 580 znaków

2011-08-11 12:44
0

@cppppppp bo najpierw sprawdzany jest sam fakt istnienia niejednoznacznych odwołań, a dopiero potem to czy w ogóle możesz sie do nich odwołać. Tzn nie ma znaczenia czy będzie to dziedziczenie public, protected czy private - jeśli znajdzie sie niejednoznaczność to będzie błąd, nawet jeśli w danym kontekście tylko jedna opcja jest dostępna.

Pozostało 580 znaków

2011-08-11 12:46
cppppppp
0
krwq napisał(a)

ale skoro B dziedziczy po A, to w instance managarze znajdą się również klasy bazowe B z klasy A, więc wystarczy że podziedziczysz po A, a następnie wywołasz sobie składową wirtualną

nie o to chodzi. InstanceManager ma zliczać kolejne instancje danych typów. jeśli utworzę 1 obiekt A, 1 B, 2 C i 1D, to
A::getNumberOfInstances() == 6
B::getNumberOfInstances() == 2
C::getNumberOfInstances() == 3
D::getNumberOfInstances() == 1

jeśli bym dziedziczył wirtualnie, to oczywiście te wyniki będą inne, zaraz napiszę do tego testy

Pozostało 580 znaków

2011-08-11 12:47
cppppppp
0

krwq, shalom, dzięki za odpowiedzi, na razie działa ;)

Pozostało 580 znaków

2011-08-11 12:47
0

jak ci się nie chce tak długo pisać to już lepiej zrobić:
#define IC(a) InstancesController<a>


░█░█░█░█░█░█░█░█░█░█░█░
edytowany 1x, ostatnio: krwq, 2011-08-11 12:47

Pozostało 580 znaków

2011-08-11 12:51
cppppppp
0
krwq napisał(a)

jak ci się nie chce tak długo pisać to już lepiej zrobić:
#define IC(a) InstancesController<a>

od jakiegoś czasu jestem uczniem nowej szkołu, #define to zło i szatan :)

Taaaa...to spróbuj napisać funkcję,która jako parametry domyślne,nie podawane przez programistę przyjmuje numer linii w której została wywołana oraz nazwę pliku z miejsca wywołania ;] - MasterBLB 2011-08-11 13:07

Pozostało 580 znaków

2011-08-11 14:13
cppppppp
0

Taaaa...to spróbuj napisać funkcję,która jako parametry domyślne,nie podawane przez programistę przyjmuje numer linii w której została wywołana oraz nazwę pliku z miejsca wywołania ;]

no bez przesady... includów i informacji debugowych nie zrobi się inaczej niż preprocesorem, ale tam gdzie można, należy go unikać

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0