基本クラスにキャストした後、EDIT 2:保存派生クラス型
前の溶液(「EDIT 1」)switch
では動作しないだろうが、私は実際にそれがしたかったです。私はconstexpr
compile time counterを見つけたので、私はswitch
を使うことができた。 Visual Studio 2015 IDEはコンパイル時のカウンタ値を(まだ)constexpr
と判断できず、すべて同じであると思っていますが、うまくコンパイルできます。私の更新ソリューションは、以下見つけることができます:
#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;
}
EDIT 1:
ライアンのソリューションは悪くないですが、私はさらに、約dynamic_cast
を読み、それが遅くなる可能性があることが分かりました特定の状況では一方、私はskypjackのソリューションが本当に好きで、私のコードを彼と一緒に更新しました(派生クラスから静的カウンタを隠すように少し修正しました)。
#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;
}
私はshared_ptr
ベクトル内の異なるクラスのオブジェクトを格納するために、いくつかの方法を探しています。さて、私はそれらを内部に保管すると、vector<shared_ptr<void>>
としましょう。私はクラスのタイプが緩んでいて、キャストできない部分を除いて、すべてがOKです。
enum
と基本クラス(objectWrapper
)を使用して、手動でクラスタイプを保存することに決めました。例を以下に示します。
#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;
}
私はvector<shared_ptr<objectWrapper>>
を作成し、すべての私のクラスを保存し、必要なときに、私は、元の型にキャストバックすることができますすることができますこの方法。
私の基本クラスには、派生型にキャストする代わりに使用するいくつかの他の仮想メソッドがありますが、いくつかの例外があります。私はいくつかの特定のメソッドを使うために、派生クラスにキャストする必要がありますが、キャストする前に派生クラスの型を何とか知る必要があります。私はそれを行うためのより簡単でクリーンな方法があるのだろうかと思っていましたか?
まあ...何を言うべきか分からない...天才のアイデア!私は似たようなことを試しましたが、この解決策には至っていませんでした。さて、最後に 'delete'sを追加すれば完璧です。 – FrogTheFrog