Reputation: 113
Is there a way through which we can get all the objects of a class in C++? Like in Python we can do:
class_name.objects.all()
to get all the objects of a class. What's its analog in C++, if it exists?
Upvotes: 7
Views: 13548
Reputation: 8886
You can do this yourself, but make sure you know what you're doing.
There's nothing within C++ that already does this, but it's pretty easy to do this yourself. The key is to recognize that a class can have static member variables and functions (i.e. functions that belong to the whole class, rather than to individual objects of the class).
So you can use some kind of table or other data structure to store a reference to each object. Like so:
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;
}
//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;
}
Note: The above design is very basic and not complete, but just meant to give you an idea of how to implement what you're asking for using static members/functions. For example, for operations that you want to perform on all the objects, for example, it may be better to implement a static function that iterates through the map of elements, rather than getting the map and then doing the iterations "outside".
I've never used this method myself, but one potential use case I can think of is e.g. in a graphics or game application, where you may want to only draw objects that are in scope and change certain drawing-related properties of all of them at once, e.g. color or size. I'm working on an application that might eventually need something like this (sort of a visual debugger). I'm sure people can provide more examples in the comments.
The picture gets complicated when inheritance is involved.
Upvotes: 14
Reputation: 26409
No, unless you implement this mechanism yourself. By default, it is not provided by the C++ language.
You can implement this mechanism yourself quite easily. Register the class in some kind of table within the constructor, and unregister within the destructor. As long as you follow the rule of three, it'll work fine.
Upvotes: 4
Reputation: 20063
As has already been stated C++ does not provide a mechanism to do this automatically. However (again has already been stated in the comments) you can use one of the standard library containers to maintain a list of created objects and then register them in the constructor and unregister them in the destructor. The example below shows one way to do this...
#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();
}
}
The above example produces the following output
I'm a class Foo object @ 003FED00
I'm a class Bar object @ 003FED30
I'm a class Foo object @ 003FED60
I'm a class Bar object @ 003FED90I'm a class Foo object @ 003FED00
I'm a class Foo object @ 003FED60I'm a class Bar object @ 003FED30
I'm a class Bar object @ 003FED90
Upvotes: 2
Reputation: 307
There is no way that I know of but you can implement one with static
members
#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;
}
}
Upvotes: 5
Reputation: 1616
Of course there is. Just use Factory pattern to create and destroy all your objects and, in Factory implementation, return a collection of live objects in a Factory function that you will provide.
Upvotes: 2