C++ でクラスのすべてのオブジェクトを取得できる方法はありますか? Python のように実行できます。
class_name.objects.all()
クラスのすべてのオブジェクトを取得するには、C++ でその類似物が存在する場合、それは何ですか?
これは自分で行うことができますが、自分が何をしているのかを確認してください。
C++ 内で既にこれを行っているものはありませんが、これを自分で行うのは非常に簡単です。重要なのは、クラスが静的メンバー変数と関数 (つまり、クラスの個々のオブジェクトではなく、クラス全体に属する関数) を持つことができることを認識することです。
したがって、ある種のテーブルまたはその他のデータ構造を使用して、各オブジェクトへの参照を格納できます。そのようです:
class A {
public:
//constructor assigns this object an id based on the static value curID,
//which is common to the class (i.e. the next class to call the constructor
//will be assigned an id thats 1 more than this one
//also, constructor adds the pointer to this object to a static map of ids
//to objects. This way, the map can be queried for the pointer to an object
//that has a particular id
A() {
id = curID++;
objects[id] = this;
}
//copy constructor ensures an object copied from another does not
//take the id of the other object, and gets added to the map
A(const A&) {
id = curID++; //don't want have the same ID as the object we are copying from
objects[id] = this;
x = A.x;
y = A.y;
}
A& operator=(const A&) {
id = curID++;
objects[id] = this;
x = A.x;
y = A.y;
return *this;
}
//destructor removes the pointer to this object from the map
~A() {
objects.erase(id);
}
//function to get the map that stores all the objects
static map<int, A*>& GetMapOfObjects() {
return objects;
}
private:
//the following variable is **static**, which means it does not
//belong to a single object but to the whole class. Here, it is
//used to generate a unique ID for every new object that's
//instantiated. If you have a lot of objects (e.g. more than
//32,767), consider using a long int
static int curID;
//this variable is also static, and is map that stores a pointer
//to each object. This way, you can access the pointer to a
//particular object using its ID. Depending on what you need, you
//could use other structures than a map
static map<int, A*> objects;
//this is a (non-static) member variable, i.e. unique to each object.
//Its value is determined in the constructor, making use of curID.
int id;
//these are some other member variables, depending on what your object actually is
double x;
double y;
}
注: 上記の設計は非常に基本的なものであり、完全ではありませんが、静的メンバー/関数を使用して求めているものを実装する方法のアイデアを提供することを目的としています. たとえば、すべてのオブジェクトに対して実行する操作の場合、マップを取得して「外部」で反復を行うよりも、要素のマップを反復処理する静的関数を実装する方がよい場合があります。
私はこの方法を自分で使用したことはありませんが、考えられるユースケースの 1 つは、たとえば、スコープ内のオブジェクトのみを描画 し、それらすべての特定の描画関連プロパティを変更したいグラフィックまたはゲーム アプリケーションです。たとえば、色やサイズなどです。最終的にこのようなもの (一種のビジュアル デバッガー) が必要になる可能性のあるアプリケーションに取り組んでいます。コメントでもっと多くの例を提供できると確信しています。
継承が関係する場合、状況は複雑になります。
私が知っている方法はありませんが、static
メンバーで実装できます
#include <iostream>
#include <vector>
class MyClass{
private:
static std::vector<MyClass*> objList;
public:
MyClass() {
objList.push_back(this);
}
static std::vector<MyClass*> getAllObjects(){
return objList;
}
};
std::vector<MyClass*> MyClass::objList;
main(){
MyClass m,a;
for (int i=0;i<MyClass::getAllObjects().size();i++){
std::cout<<MyClass::getAllObjects()[i]<<std::endl;
}
}
もちろんあります。Factory パターンを使用してすべてのオブジェクトを作成および破棄し、Factory 実装では、提供する Factory 関数でライブ オブジェクトのコレクションを返します。
すでに述べたように、C++ はこれを自動的に行うメカニズムを提供していません。ただし (これもコメントに記載されています)、標準ライブラリ コンテナーの 1 つを使用して、作成されたオブジェクトのリストを維持し、それらをコンストラクターに登録して、デストラクターで登録解除することができます。以下の例は、これを行う1つの方法を示しています...
#include <iostream>
#include <memory>
#include <utility>
#include <map>
#include <algorithm>
#include <iterator>
#include <typeinfo>
#include <vector>
class Object
{
static std::map<const Object*, Object*> objects_;
public:
Object()
{
objects_.insert(std::make_pair(this, this));
}
virtual ~Object()
{
objects_.erase(this);
}
static std::vector<Object*> get_all()
{
std::vector<Object*> o;
o.reserve(objects_.size());
for (auto obj : objects_)
{
o.push_back(obj.second);
}
return std::move(o);
}
template<class Type>
static std::vector<Type*> get_bytype()
{
std::vector<Type*> o;
for(auto obj : objects_)
{
Type *t = dynamic_cast<Type*>(obj.second);
if (t != nullptr)
{
o.push_back(t);
}
};
return std::move(o);
}
void print() const
{
std::cout << "I'm a " << typeid(*this).name() << " object @ " << this << std::endl;
}
};
std::map<const Object*, Object*> Object::objects_;
class Foo : public Object {};
class Bar : public Object {};
int main()
{
std::unique_ptr<Object> o1 = std::unique_ptr<Object>(new Foo());
std::unique_ptr<Object> o2 = std::unique_ptr<Object>(new Bar());
std::unique_ptr<Object> o3 = std::unique_ptr<Object>(new Foo());
std::unique_ptr<Object> o4 = std::unique_ptr<Object>(new Bar());
std::vector<Object*> objects = Object::get_all();
for (auto o : objects)
{
o->print();
}
std::cout << "-----" << std::endl;
std::vector<Foo*> foos = Object::get_bytype<Foo>();
for (auto o : foos)
{
o->print();
}
std::cout << "-----" << std::endl;
std::vector<Bar*> bars = Object::get_bytype<Bar>();
for (auto o : bars)
{
o->print();
}
}
上記の例では、次の出力が生成されます
私はクラス Foo オブジェクトです @ 003FED00
私はクラス Bar オブジェクトです @ 003FED30
私はクラス Foo オブジェクトです @ 003FED60
私はクラス Bar オブジェクトです @ 003FED90私はクラス Foo オブジェクトです @ 003FED00
私はクラス Foo オブジェクトです @ 003FED60I'm a class Bar object @ 003FED30
私はクラス Bar object @ 003FED90