vector in template



  • hallo,
    ich habe das problem, dass ich auf eine template klasse casten müsste, damit ich auf ihre funktion zugreifen kann:

    template <class T>
    class templateWithVector {
    public:
    	std::vector<T*>vec;
    
    	T *getFromVector(unsigned int idx) {
    		if (idx < vec.size())
    			return vec.at(idx);
    		return nullptr;
    	}
    };
    
    class classBase {};
    class bSpecifics{};
    
    class B : public classBase, public templateWithVector<bSpecifics> {
    public:
    	B() {
    		for (int i = 0; i < 3; i++)
    			vec.push_back(new bSpecifics());
    	}
    };
    

    wie kann ich jetzt auf getFromVector zugreifen?:

    classBase *myB = new B();
    myB->getFromVector(1);  // das kompiliert ja nun leider nicht
    

    virtuelle funktionen gehen nicht in templates, casten auch nicht, oder?



  • Warum benutzt du die Basisklasse?
    Und nicht einfach

    B *myB = new B();
    

    ?



  • Th69 schrieb:

    Warum benutzt du die Basisklasse?
    Und nicht einfach

    B *myB = new B();
    

    ?

    Das ist im Zusammenhang meines Programms ein zentrales Element. Es gibt viele classBase , aber nur wenige davon sind templareWithVector.
    Irgendwie bekomme ich die OOP Logik mit templates nicht zusammen.



  • Also so?

    classBase *myB = new B();
    templateWithVector<bSpecifics> *p = dynamic_cast<templateWithVector<bSpecifics>*>(myB);
    if (p != null)
        p->getFromVector(1);
    

    Edit: besser den dynamic_cast abfragen...



  • Th69 schrieb:

    Also so?

    classBase *myB = new B();
    templateWithVector<bSpecifics> *p = dynamic_cast<templateWithVector<bSpecifics>*>(myB);
    if (p != null)
        p->getFromVector(1);
    

    Edit: besser den dynamic_cast abfragen...

    Hmmm, vielleicht hab ich zu stark minimalisiert, es gibt auch noch class C : public tenplateWithVector<cSpecifics>. Ich muss also ausgehend von einer classBase, von der ich weiß, dass sie ein templateWithVector ist, auf eine function von templateWithVector zugreifen. Deswegen der Gedanke, dass es toll wäre zu templateWithVector<T> casten zu können, was aber leider nicht geht.



  • Hat denn classBase einen virtuellen Destruktor?

    Bei mir läuft es: Ideone-Code



  • Th69 schrieb:

    Hat denn classBase einen virtuellen Destruktor?

    Bei mir läuft es: Ideone-Code

    oh, cool, das mit dem virtuellen destruktor war mir neu, danke!
    ich hatte gehofft, dass ich wie bei der oop logik nicht auf einen spezifischen typ B oder C casten muss, sondern ohne diese spezifizierung auf templateWithVector::getFromVector zugreifen könnte. ich brauche das an mehreren stellen und müsste dann später bei der einführung einer klasse D alle stellen per hand ändern.
    ich vermute, dass ich das vergessen kann. ist es ratsam das alles komplett anders zu entwerfen?


  • Mod

    mael15 schrieb:

    ich hatte gehofft, dass ich wie bei der oop logik nicht auf einen spezifischen typ B oder C casten muss, sondern ohne diese spezifizierung auf templateWithVector::getFromVector zugreifen könnte.

    Das dürfte in keiner statisch typisierten Sprache funktionieren.

    mael15 schrieb:

    ich brauche das an mehreren stellen und müsste dann später bei der einführung einer klasse D alle stellen per hand ändern.
    ich vermute, dass ich das vergessen kann. ist es ratsam das alles komplett anders zu entwerfen?

    Möglich.
    Eventuell ist es aber so, dass der Code, der den cast enthalten muss, eine Funktionalität implementiert, die logisch vom B-Objekt selbst abhängt, und im Grunde für alle classBase-Objekte existiert. Dann sollte dieser Code in einer virtuellen Funktion erscheint, die in B entsprechend überschrieben ist.
    Etwa so:

    #include <iostream>
    #include <vector>
    using namespace std;
    
    template <class T>
    class templateWithVector {
    public:
        std::vector<T*> vec;
    
        T* getFromVector(unsigned int idx) const { return idx < vec.size() ? vec[idx] : nullptr; }
    };
    
    class classBase {
    public:
        virtual std::ostream& doGet(std::ostream& s) const { return s; } // do nothing by default
        virtual ~classBase(){};
    };
    class bSpecifics {};
    
    class B : public classBase, public templateWithVector<bSpecifics> {
    public:
        B() {
            for (int i = 0; i < 3; i++)
                vec.push_back(new bSpecifics());
        }
        virtual std::ostream& doGet(std::ostream& s) const override {
            return s << "B: " << getFromVector(1) << '\n';
        }
    };
    
    class C : public classBase {
    };
    
    int main() {
        classBase&& myB = B();
        myB.doGet(std::cout);
        classBase&& myC = C();
        myC.doGet(std::cout);
    }
    


  • ja, das ginge. ich habe aber sehr viele andere classBase, die kein doGet brauchen würden. ich würde gerne alles so übersichtlich und minimal wie möglich halten.

    mittlerweile habe ich mich der lösung meines sehr spezifischen problems mit hilfe eines interface weitgehend genähert:

    class specificsBase {};
    
    class templateWithVectorInterface {
    public:
    	virtual specificsBase *getFromVector(unsigned int idx) = 0;
    };
    
    template <class T>
    class templateWithVector : public templateWithVectorInterface {
    public:
    	std::vector<T*>vec;
    
    	T *getFromVectorTyped(unsigned int idx) {
    		if (idx < vec.size())
    			return vec.at(idx);
    		return nullptr;
    	}
    
    	specificsBase *getFromVector(unsigned int idx) {
    		specificsBase *ret = getFromVectorTyped(idx);
    		return ret;
    	}
    
    	~templateWithVector() {
    		for (auto v : vec)
    			delete v;
    		vec.clear();
    	}
    };
    
    class classBase {
    public:
    	virtual ~classBase() {};
    };
    
    class bSpecifics : public specificsBase{};
    class B : public classBase, public templateWithVector<bSpecifics> {
    public:
    	B() {
    		for (int i = 0; i < 3; i++)
    			vec.push_back(new bSpecifics());
    	}
    };
    
    class cSpecifics : public specificsBase {};
    class C : public classBase, public templateWithVector<cSpecifics> {
    public:
    	C() {
    		for (int i = 0; i < 3; i++)
    			vec.push_back(new cSpecifics());
    	}
    };
    

    dadurch kann ich ohne konkretes wissen um die spezifische klasse trotzdem das template nutzen:

    classBase *myB = new B();
    
    templateWithVectorInterface *bCast = dynamic_cast<templateWithVectorInterface*>(myB);
    if (bCast) {
    	specificsBase *baseSpec = bCast->getFromVector(1);
    	// etc....
    }
    
    delete myB;
    

Log in to reply