EDIT 2 Gießen:Speichern abgeleiteten Klasse Typ, nachdem es auf Basisklasse
Vorherige Lösung („EDIT 1“) nicht mit switch
arbeiten, aber ich wollte es wirklich. Nachdem ich etwas um Google gegraben habe, habe ich constexpr
compile time counter entdeckt, was mir erlauben würde, switch
zu verwenden. Visual Studio 2015 IDE ist nicht in der Lage, constexpr
Kompilierzeit Zählerwerte (noch) zu bestimmen und denke, dass sie alle gleich sind, aber es kompiliert einfach gut.
#include <iostream>
#include <memory>
#include <vector>
namespace compileTimeCounter {
template<int N>
struct flag {
friend constexpr int adl_flag(flag<N>);
};
template<int N>
struct writer {
friend constexpr int adl_flag(flag<N>) {
return N;
}
static constexpr int value = N;
};
template<int N, class = char[noexcept(adl_flag(flag<N>())) ? +1 : -1]>
int constexpr reader(int, flag<N>) {
return N;
}
template<int N>
int constexpr reader(float, flag<N>, int R = reader(0, flag<N - 1>())) {
return R;
}
int constexpr reader(float, flag<0>) {
return 0;
}
template<int N = 1, int C = reader(0, flag<32>())>
int constexpr next(int R = writer<C + N>::value) {
return R;
}
}
class objectWrapper {
public:
virtual size_t getType() const noexcept = 0;
};
template<typename T>
class typeWrapper : public objectWrapper {
public:
static constexpr size_t type = compileTimeCounter::next();
size_t getType() const noexcept { return this->type; }
};
class classA : public typeWrapper<classA> {
public:
classA() { std::cout << "classA ctor" << std::endl; }
~classA() { std::cout << "classA dtor" << std::endl; }
void methodA() { std::cout << "methodA called" << std::endl; }
};
class classB : public typeWrapper<classB> {
public:
classB() { std::cout << "classB ctor" << std::endl; }
~classB() { std::cout << "classB dtor" << std::endl; }
void methodB() { std::cout << "methodB called" << std::endl; }
};
class classC : public typeWrapper<classC> {
public:
classC() { std::cout << "classC ctor" << std::endl; }
~classC() { std::cout << "classC dtor" << std::endl; }
void methodC() { std::cout << "methodC called" << std::endl; }
};
int main() {
std::vector<std::shared_ptr<objectWrapper>> objects1, objects2;
objects1.push_back(std::make_shared<classA>());
objects1.push_back(std::make_shared<classB>());
objects1.push_back(std::make_shared<classC>());
objects2 = objects1;
switch (objects2[0]->getType()) {
case classA::type:
reinterpret_cast<classA*>(objects2[0].get())->methodA();
break;
case classB::type:
reinterpret_cast<classB*>(objects2[0].get())->methodB();
break;
case classC::type:
reinterpret_cast<classC*>(objects2[0].get())->methodC();
break;
}
objects2.~vector();
std::cout << "objects2 destroyed" << std::endl;
objects1.~vector();
std::cout << "objects1 destroyed" << std::endl;
std::cin.get();
return 0;
}
1 EDIT:
Während Ryan-Lösung ist nicht schlecht, ich lese weiter über dynamic_cast
und fand heraus, dass es langsam sein könnte meine aktualisierte Lösung finden Sie unten in bestimmten Situationen. Auf der anderen Seite mag ich skypjacks Lösung sehr und habe meinen Code mit seinem (leicht modifizierten, um statischen Zähler aus abgeleiteten Klassen zu verstecken) aktualisiert.
#include <iostream>
#include <memory>
#include <vector>
template<typename T>
struct typeWrapper;
struct objectWrapper {
template<typename T>
friend struct typeWrapper;
private:
static size_t typeCounter;
public:
virtual size_t getType() const noexcept = 0;
};
size_t objectWrapper::typeCounter = 0;
template<typename T>
struct typeWrapper : objectWrapper {
static const size_t type;
size_t getType() const noexcept { return this->type; }
};
template<typename T>
const size_t typeWrapper<T>::type = objectWrapper::typeCounter++;
class classA : public typeWrapper<classA> {
public:
classA() { std::cout << "classA ctor" << std::endl; }
~classA() { std::cout << "classA dtor" << std::endl; }
void methodA() { std::cout << "methodA called" << std::endl; }
};
class classB : public typeWrapper<classB> {
public:
classB() { std::cout << "classB ctor" << std::endl; }
~classB() { std::cout << "classB dtor" << std::endl; }
void methodB() { std::cout << "methodB called" << std::endl; }
};
class classC : public typeWrapper<classC> {
public:
classC() { std::cout << "classC ctor" << std::endl; }
~classC() { std::cout << "classC dtor" << std::endl; }
void methodC() { std::cout << "methodC called" << std::endl; }
};
int main() {
std::vector<std::shared_ptr<objectWrapper>> objects1, objects2;
objects1.push_back(std::make_shared<classA>());
objects1.push_back(std::make_shared<classB>());
objects1.push_back(std::make_shared<classC>());
objects2 = objects1;
if (objects2[0]->getType() == classA::type)
reinterpret_cast<classA*>(objects2[0].get())->methodA();
else if (objects2[0]->getType() == classB::type)
reinterpret_cast<classB*>(objects2[0].get())->methodB();
else if (objects2[0]->getType() == classC::type)
reinterpret_cast<classC*>(objects2[0].get())->methodC();
objects2.~vector();
std::cout << "objects2 destroyed" << std::endl;
objects1.~vector();
std::cout << "objects1 destroyed" << std::endl;
std::cin.get();
return 0;
}
ich nach einer Möglichkeit suchen andere Klasse Objekte in shared_ptr
Vektor zu speichern. Jetzt, wenn ich sie innen aufbewahre, sagen wir vector<shared_ptr<void>>
, ist alles in Ordnung, außer für den Teil, wo ich meinen Klassentyp verliere und nicht zurückwerfen kann.
Ich habe beschlossen, den Klassentyp manuell zu speichern, indem enum
und Basisklasse (objectWrapper
) verwendet wird. Beispiel ist unten gezeigt.
#include <iostream>
#include <memory>
#include <vector>
#include <inttypes.h>
enum class objectType : uint8_t {
classA,
classB,
classC
};
class objectWrapper {
protected:
objectType type;
objectWrapper(objectType type) : type(type) {}
public:
virtual objectType getObjectType() {
return this->type;
}
};
class classA : public objectWrapper {
public:
classA() : objectWrapper(objectType::classA) {
std::cout << "classA ctor" << std::endl;
}
~classA() { std::cout << "classA dtor" << std::endl; }
void methodA() { std::cout << "methodA called" << std::endl; }
};
class classB : public objectWrapper {
public:
classB() : objectWrapper(objectType::classB) {
std::cout << "classB ctor" << std::endl;
}
~classB() { std::cout << "classB dtor" << std::endl; }
void methodB() { std::cout << "methodB called" << std::endl; }
};
class classC : public objectWrapper {
public:
classC() : objectWrapper(objectType::classC) {
std::cout << "classC ctor" << std::endl;
}
~classC() { std::cout << "classC dtor" << std::endl; }
void methodC() { std::cout << "methodC called" << std::endl; }
};
int main() {
std::vector<std::shared_ptr<objectWrapper>> objects1, objects2;
objects1.push_back(std::make_shared<classA>());
objects1.push_back(std::make_shared<classB>());
objects1.push_back(std::make_shared<classC>());
objects2 = objects1;
switch (objects2[0]->getObjectType()) {
case objectType::classA:
dynamic_cast<classA*>(objects2[0].get())->methodA();
break;
case objectType::classB:
dynamic_cast<classB*>(objects2[0].get())->methodB();
break;
case objectType::classC:
dynamic_cast<classC*>(objects2[0].get())->methodC();
break;
default:
break;
}
objects2.~vector();
std::cout << "objects2 destroyed" << std::endl;
objects1.~vector();
std::cout << "objects1 destroyed" << std::endl;
std::cin.get();
return 0;
}
So kann ich vector<shared_ptr<objectWrapper>>
und speichern alle meine Klassen und bei Bedarf erstellen können, kann ich auf ihre ursprünglichen Arten zurückgeworfen.
Während meine Basisklasse über einige andere virtuelle Methoden verfügt, die ich anstelle des abgeleiteten Typs verwenden werde, gibt es einige Ausnahmen. Ich muss zur abgeleiteten Klasse zurückkehren, um einige spezifische Methoden zu verwenden, aber ich muss den abgeleiteten Klassentyp irgendwie kennen, bevor ich ihn umwandeln kann. Ich habe mich gefragt, ob es einen einfacheren und saubereren Weg gibt, es zu tun?
Nun ... Ich weiß nicht was ich sagen soll ... Genius Idee! Ich habe etwas Ähnliches versucht, war aber dieser Lösung nicht einmal nahe.Nun, wenn Sie einfach 'delete' am Ende hinzufügen, wäre es perfekt. – FrogTheFrog