Automatically register new derived class / creator method - c++

I guess it'll be easiest if I give an example of what I'm trying to achieve.
Let's say I'd like to implement a unit testing environment, in which implementing a new unit test would involve deriving from a given base class and (possibly) following guidlines involving putting additional macros. Such new test would then be automatically added to list of tests, ran one after another at some point. Two things however:
I'm trying to make creating each new test as quick and easy as possible, especially when it comes to modifying files other than the files with the test itself. A perfect situation would be such, that implementing a new test wouldn't require touching any other files in the project. This is achievable with singletons and possibly CRTP, but now comes point number 2,
The target is an MCU with limited amount of RAM (ROM in general is not a problem) and I'd like to be able to run the tests directly on the target platform. Because of this, static objects occupying memory throughout the entire application lifetime are not acceptable. Instead, I'd like to be able to create and delete each test separately only at the time it needs to be ran.
Basically, the problem comes down to a way of automatically registering derived types - or creator methods - to a factory with minimum RAM overhead (I'm assuming there will be some, i.e. at least pointers to said methods).
Sorry for no code samples, but there's really nothing to show here without already committing to one given implementation.

Could you create a static/global vector of function pointers. These would be pointers to creator/factory functions for each test class. The factory functions return pointers to the base test class. I was going to try to write it out, but I think code is easier to write and understand.
class TestBase
{
public:
static char registerTest(<function ptr type> creator) {
testCreators.push_back(creator);
return 1;
}
static void runTests()
{
for (auto creator : testCreators)
{
auto newTestClass = creator();
newTestClass->tests();
delete newTestClass;
}
}
private:
void tests() = 0;
std::vector<function ptr type> testCreators;
};
Then the derived class.
class SpecificTest : public TestBase
{
// Pretend test code is here.
private:
static char dummy;
};
// Plan old C function. Need to establish naming conventions so as
// not to get multiple symbol errors during linking. Kind of fragile.
TestBase* specificTestCreator()
{
return new SpecificTest();
}
In the .cpp file for SpecificTest
char SpecificTest::dummy = TestBase::registerTest(specificTestCreator);
I have tried to compile or run this, but I think it's fundamentally sound.

I've created an example based on the answer provided by Michael, compiled and ran it. Posting code below.
TestBase.h:
#ifndef TESTBASE_H_
#define TESTBASE_H_
#include <vector>
class TestBase {
public:
TestBase();
virtual ~TestBase();
static void RunAllTests();
protected:
virtual void test() = 0;
static char addTestCreator(TestBase* (*creator)());
private:
static std::vector<TestBase* (*)()> &getTests();
};
#endif /* TESTBASE_H_ */
TestBase.cpp
#include "TestBase.h"
TestBase::TestBase() {
}
TestBase::~TestBase() {
}
char TestBase::addTestCreator(TestBase* (*creator)())
{
getTests().push_back(creator);
return 0;
}
void TestBase::RunAllTests()
{
for(std::vector<TestBase* (*)()>::iterator it = getTests().begin(); it != getTests().end(); it++)
{
TestBase *t = (*it)();
t->test();
delete t;
}
}
std::vector<TestBase* (*)()> &TestBase::getTests()
{
static std::vector<TestBase* (*)()> v;
return v;
}
ConcreteTest1.h:
#ifndef CONCRETETEST1_H_
#define CONCRETETEST1_H_
#include "TestBase.h"
class ConcreteTest1: public TestBase {
public:
ConcreteTest1();
virtual ~ConcreteTest1();
protected:
void test();
private:
// both here can be expanded with a macro to make it
// easier as they'll be same for all derived classes
static char dummy;
static TestBase *creator();
};
#endif /* CONCRETETEST1_H_ */
ConcreteTest1.cpp:
#include "ConcreteTest1.h"
#include <iostream>
// can be expanded with a macro
char ConcreteTest1::dummy = TestBase::addTestCreator(ConcreteTest1::creator);
// can be expanded with a macro
TestBase* ConcreteTest1::creator()
{
return new ConcreteTest1();
}
ConcreteTest1::ConcreteTest1()
{
std::cout << "Creating test 1" << std::endl;
}
ConcreteTest1::~ConcreteTest1()
{
std::cout << "Deleting test 1" << std::endl;
}
void ConcreteTest1::test()
{
std::cout << "Running test 1" << std::endl;
}
Similarly ConcreteTest2.cpp/.h.
Invoked from main with:
TestBase::RunAllTests();
Output is:
Creating test 1
Running test 1
Deleting test 1
Creating test 2
Running test 2
Deleting test 2
which is exactly what I've wanted to achieve.

Related

How to hold a List<> of opaque handles in CLI/C++?

I am writing a CLI/C++ wrapper for a C-library in order to use it in C#. It must be said, I only have access to the C header file and the .lib of the C-library, not the source code.
Some of the functions I am trying to wrap are returning opaque handles, such as:
typedef struct SanEvent_s *SanEvent;
typedef struct SanValue_s *SanValue;
Returning objects of this type on the C# end seems like trouble to me, as I don't know the implementation of the struct (I tried returning the SanEvent type in the C++ wrapper but on the C# end that type is not accessible due to "protection level" or whatever it said). My plan at the moment is therefore to write some helper functions, which instead just return an integer which represents an, for example, San Event in a list or something. The list would be kept in the managed C++ wrapper, where I can actually manage the San Event type.
My problem is, I don't really know how to do this with this type of type.
This:
using System::Collections::Generic::List;
namespace Wrapper {
public ref class Analytics
{
private:
static List<SanEvent^>^ events = gcnew List<SanEvent^>();
}
}
Gives me the errors: handle to handle, pointer, or reference is not allowed
The right hand side also complains about expected type specifier + the same error as above.
Can anyone give me some tips on how I could tackle this issue neatly and efficiently? My List implementation is not carved in stone, and I am open to better suggestions.
Let's imagine following SanEvent declaration
struct SanEvent_s
{
int test;
};
typedef SanEvent_s *SanEvent;
And following C++ API to work with such event:
SanEvent GetEvent()
{
auto e = new SanEvent_s();
e->test=42;
return e;
}
int UseEvent(SanEvent pEvent)
{
return pEvent->test;
}
All this code contained in static library project (fully native, no CLR).
Then we have C++/CLI project to wrap this static lib.
Here we have wrapper for event itself:
#include "./../CppLib/SanEvent_s.h"
public ref class SanEventWrapper: Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid
{
public:
static SanEventWrapper^ GetWrapper()
{
return gcnew SanEventWrapper(GetEvent());
}
internal:
SanEventWrapper(SanEvent event):SafeHandleZeroOrMinusOneIsInvalid(true)
{
this->e = event;
this->handle = System::IntPtr(event);
}
int UseWrapper()
{
return ::UseEvent(this->e);
}
protected:
bool ReleaseHandle() override
{
//todo: release wrapped event
return true;
}
private:
SanEvent e;
};
And another class which uses such a wrapper
public ref class SanEventConsumer
{
public:
int ConsumeEvent(SanEventWrapper^ wrapper)
{
return wrapper->UseWrapper();
}
};
And finally, how to use all this from C#:
var wrapper = SanEventWrapper.GetWrapper();
var consumer = new SanEventConsumer();
var res = consumer.ConsumeEvent(wrapper);
Console.WriteLine(res);
This should print 42;
Notes:
Notes:
this is a very simplified sample. It should be adapted ytrin accordance with semantics of 'SanEvent' struct as well as with respect of requirements of SafeHandle documentation (https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.safehandle?view=netframework-4.8 and https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.safehandles.safehandlezeroorminusoneisinvalid?view=netframework-4.8)
you should decide if your wrapper will own the SunEvent object or not and implement ReleaseHandle and Dispose accordingly to this.
you may consider to use another base class from this list https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.safehandles?view=netframework-4.8 instead of 'SafeHandleZeroOrMinusOneIsInvalid' or even make direct inhernitance from SafeHandle.
you can even think about dropping SafeHandle-related stuff at all and making the simple wrapper by your own, but it can give some surprises in connection with GC.
depending of the semantics of the SunEvent you may be also need to implement factory to guarantee that you always return to the managed code the same instance of wrapper for all equals values of raw native pointer.
Here's something similar to what #Serg has above, but explicitly goes with the idea that you have NO IDEA in the C# world what's inside the object.
So if you have a C++/CLI library made in VS, you get this in the .h file:
#pragma once
#include <cstdint>
using namespace System;
namespace CppCliLibrary {
public ref class Class1
{
public:
static IntPtr getOpaqueInstance(int32_t argument);
static void useOpaqueInstance(IntPtr obj);
static void freeOpaqueInstance(IntPtr obj);
};
}
Like above, using IntPtr to represent a pointer to "whatever". The corresponding .cpp file is this:
#include "pch.h"
#include "CppCliLibrary.h"
#include <string>
#include <iostream>
namespace CppCliLibrary
{
class OpaqueCppClass
{
public:
OpaqueCppClass(int32_t arg)
: m_int(arg) { }
int32_t m_int;
};
}
IntPtr CppCliLibrary::Class1::getOpaqueInstance(int32_t argument)
{
return IntPtr(new OpaqueCppClass(argument));
}
void CppCliLibrary::Class1::useOpaqueInstance(IntPtr obj)
{
CppCliLibrary::OpaqueCppClass* deref = reinterpret_cast<CppCliLibrary::OpaqueCppClass *>(obj.ToPointer());
std::cout << "Contents of class are: " << deref->m_int << std::endl;
}
void CppCliLibrary::Class1::freeOpaqueInstance(IntPtr obj)
{
CppCliLibrary::OpaqueCppClass* deref = reinterpret_cast<CppCliLibrary::OpaqueCppClass*>(obj.ToPointer());
std::cout << "Deleting class with contents: " << deref->m_int << std::endl;
delete deref;
}
Then in the C# file you have this:
namespace CsCoreConsole
{
class Program
{
static void Main(string[] args)
{
// Get an instance
var instance = CppCliLibrary.Class1.getOpaqueInstance(52);
// Use it
Console.WriteLine("Got an instance we're using");
CppCliLibrary.Class1.useOpaqueInstance(instance);
Console.WriteLine("Freeing it");
CppCliLibrary.Class1.freeOpaqueInstance(instance);
// Add a bunch to a list
List<IntPtr> opaqueInstances = new List<IntPtr>();
for(int i = 0; i < 5; i++)
{
opaqueInstances.Add(CppCliLibrary.Class1.getOpaqueInstance(i * 10));
}
// Use them all
foreach(var cur in opaqueInstances)
{
CppCliLibrary.Class1.useOpaqueInstance(cur);
}
// Delete them all
foreach (var cur in opaqueInstances)
{
CppCliLibrary.Class1.freeOpaqueInstance(cur);
}
}
}
}
Of course the C# project needs to reference the C++/CLI one, but you get the idea here. The C++/CLI is a factory (nothing more, nothing less) for IntPtr and it can use it as well, because to C# it's opaque. C# knows of nothing more than IntPtr.
The idea from Serg is to wrap it more, in a type-safe way. Sure, that can work, but this is the "even more raw" variant, if you want to put it "directly" into a List<>

How to share objects in c++ across libraries

Suppose I have a program like this:
File main.cpp
#include "something.hpp"
int main(int argc, char* argv[]) {
some = new Something();
return 0;
}
which will be linked to a .so library consisting of following files:
File logger.hpp
#include <iostream>
class Logger {
public:
Logger();
void log(char);
void set_name(char);
private:
char m_name;
};
File logger.cpp
#include "logger.hpp"
Logger::Logger() {}
void Logger::log(char msg) {
std::cout << this->m_name << " : " << msg;
}
void Logger::set_name(char name) {
this->m_name = name;
}
File something.hpp
#include "logger.hpp"
class Something {
public:
Something();
};
File something.cpp
#include "something.hpp"
Something::Something() {
logger->log("hello !");
}
The code as it is now will fail in something.cpp at logger->log(), because logger has never been defined. I could solve this by adding logger = new Logger(). But I want to only create a new Logger instance, if none has been created in a program / library using this library. When an instance has been created already, I can use that by adding extern Logger logger;. But this will not work, when no instance has been created. Any suggestions (is it possible at all ?) ?
Note: I am using Gtkmm4 / Glibmm2.6 already, maybe there is a solution by using Gtk or Glib ...
First approach: Singleton
As discussed in the comments, you could use the Singleton design pattern
to acheive this. However, remember that this pattern has several drawbacks,
two of which are:
Singletons allow global access.
Singletons are hard to unit test.
Which are true problems when writing quality software. Also, for your particular
case, make sure to read this answer which explains how to make sure everything
is linked appropriately so you do not end up with multiple instances of your
singleton.
Second approach: dependency injection
I decided to post an answer here to illustrate another way of doing things that
solves the two issues mentionned above: dependency injection (DI). With DI,
you do not create your dependencies, you inject them through parameters. For
example, instead of:
Something::Something() {
auto logger = new Logger(); // Dependency creation (not injection)
logger->log("hello !");
}
you would have something like:
Something::Something(Logger* p_logger) { // Logger dependency injected through p_logger
p_logger->log("hello !");
}
Note that DI does not solve the "one instance" issue by itself. Care must be taken to
create your dependencies once (usually in your main) and then pass them around as
parameters to use them. However, the global access issue is resolved.
You can bring this to another level by abstracting your dependencies. For example,
you could write an interface to your Logger class and use this instead:
// Somewhere in your library:
class ILogger
{
public:
virtual ~ILogger() = default;
virtual void log(const std::string& p_message) = 0;
virtual void set_name(const std::string& p_name) = 0;
};
// In Logger.hpp:
class Logger : public ILogger {
public:
Logger();
void log(const std::string& p_message) override;
void set_name(const std::string& p_name) override;
private:
std::string m_name;
};
// In something.hpp/cpp:
Something::Something(ILogger* p_logger) { // Logger dependency injected through p_logger
p_logger->log("hello !");
}
To acheive this your main could look like this:
int main(int argc, char* argv[]) {
// Here, you create your logger dependency:
std::unique_ptr<ILogger> concreteLogger = std::make_unique<Logger>();
concreteLogger->set_name("frederic");
// Here, you inject it. From here on, you will inject it everywhere
// in your code. The using code will have no idea that under the hood,
// you really are using the Logger implementation:
some = new Something(concreteLogger.get());
// Note: if you use `new`, do not forget to use `delete` as well. Otherwise,
// check out std::unique_ptr, like above.
return 0;
}
The advantage of this is that you can now change the implementation of your logger
at any time whithout anything (except main) caring about it. You can also create
mocks of your logger in case you want to unit test Something. This is highly
more flexible that handling the singleton in your unit tests, which in term will
create all sorts of (hard to investigate/resolve) problems. This, in terms, solves
the second issue mentionned above.
Note that a possible drawback of DI is that you may end up having lots of
parameters, but in my opinion it is still superior to using singletons.

Static member has different values

Update: I think I was able to narrow down the problem, see here for a new question that is hopefully more precise.
Update 2: I was able to solve the problem, see the link above :-)
I am trying to understand whether I got something fundamentally confused about how static member variables work.
I have a class (Lets call it cProvider) that contains static member variables (e.g. a pointer) and get/set methods. This class is included by two other classes, let's call them "cWriter" and "cReader", and both instantiate it. cWriter only accesses the setter methods, cReader accesses the getter methods.
My problem is that seem to be multiple instances of the static variables, meaning that when I access a static variable of cProvider through cWriter, it accesses a different physical location than when I access the same variable through cReader.
Is this something that is to be expected? I am doing this in a rather complex and probably unknown framework, ADTF. It might well be that the framework is responsible for this behavior. I checked the process IDs, and cWriter and cReader have the same process ID.
What could be the reason that they still access different addresses? I never had a formal programming education, so I might be missing something fundamental about how static variables work. I am happy for any hints about what could be the problem!
Edit: Condensed version of my code: (To show the gist)
OdometryHistoryWriter.h:
class cOdometryHistoryWriter
{
static bool something;
}
OdometryHistoryWriter.cpp:
bool cOdometryHistoryWriter::something;
OdometryHistoryProviderInputFilter.h:
#include OdometryHistoryWriter.h
class cOdometryHistoryProviderInputFilter
{
cOdometryHistoryWriter m_odoHistWriter;
void setSomething(boolvar);
}
OdometryHistoryProviderInputFilter.cpp:
#include OdometryHistoryProviderInputFilter.h
void OdometryHistoryProviderInputFilter::setSomething(boolvar)
{
m_odoHistWriter.something = boolvar;
return;
}
OdometryHistoryProvider.h:
class cOdometryHistoryProvider
{
bool getSomething();
cOdometryHistoryWriter m_odoHistAcessor;
}
OdometryHistoryProvider.cpp:
bool cOdometryHistoryProvider::getSomething()
{ return m_odoHistAcessor.something;}
Not really an answer, but it's far too long to make a comment, and code in comments is hopeless to read even when it fits [unless it's really short]
I just did this based on your code:
#include <iostream>
class cOdometryHistoryWriter
{
public:
static bool something;
};
bool cOdometryHistoryWriter::something = false;
class cOdometryHistoryProviderInputFilter
{
public:
cOdometryHistoryWriter m_odoHistWriter;
void setSomething(bool b) { m_odoHistWriter.something = b; }
};
class cOdometryHistoryProvider
{
public:
bool getSomething() { return m_odoHistAcessor.something; }
cOdometryHistoryWriter m_odoHistAcessor;
};
int main()
{
cOdometryHistoryProvider a;
cOdometryHistoryProviderInputFilter b;
b.setSomething(true);
std::cout << "Expect true:" << a.getSomething() << std::endl;
b.setSomething(false);
std::cout << "Expect False:" << a.getSomething() << std::endl;
}
and it outputs:
Expect true:1
Expect False:0
as you'd expect (at least I do).
As long as you only have ONE definition of bool cOdometryHistoryWriter::something = false;, it should only ever have one address, and be accessible as one and the same everywhere. If this is not happening, the there's SOMETHING different between your ACTUAL code and the code you posted (not that unusual, I expect more than half of the questions I look at are missing "the code that actually make it go wrong" [inclusive cases of "no code posted"])

Limiting includes in C++

I am having all sorts of problems with include-overload in my newbie C++ project, but I'm not sure how to avoid it.
How do I avoid the problem of having to include dozens of classes, for example in a map-loading scenario:
Here's a trivial example Map class, which will load a game-map from a file:
// CMap.h
#ifndef _CMAP_H_
#define _CMAP_H_
class CMap {
public:
CMap();
void OnLoad();
};
#endif
// CMap.cpp
#include "CMap.h"
CMap::CMap() {
}
void CMap::OnLoad() {
// read a big file with all the map definitions in it here
}
Now let's say I have a whole plethora of monsters to load into my map, so I might have a list or some other structure to hold all my monster definitions in the map
std::list<CMonster*> MonsterList;
Then I could simple forward-declare "CMonster" in my CMap.h, and add as many monsters as I like to that list
// CMap.h
class CMonster;
// CMap.cpp
void CMap::OnLoad() {
// read a big file with all the map definitions in it here
// ...
// read in a bunch of mobs
CMonster* monster;
MonsterList.push_back(monster);
}
But what if I have lots of different types of monster? How do I create lots of different types of monster without including every CMonster_XXX.h? And also use methods on those?
// CMap.cpp
void CMap::OnLoad() {
// read a big file with all the map definitions in it here
// ...
// read in a bunch of mobs
CMonster_Kitten* kitty;
kitty->OnLoad();
MonsterList.push_back(kitty);
CMonster_Puppy *puppy;
puppy->OnLoad();
puppy->SetPrey(kitty);
MonsterList.push_back(puppy);
CMonster_TRex *awesome;
awesome->OnLoad();
awesome->SetPrey(puppy);
MonsterList.push_back(awesome);
}
Here's the rule I use for including things.
Forward declare as much as you can in your header files.
include any .h you need in your .cpp
don't include .h in other .h unless you have to.
If your project build without needing to include a .h, you are fine. (mostly, provided your compiler is compliant enough)
Edit: Additionally, you may want to read Large-Scale C++ Software Design. It talks about managing physical file dependencies.
You could create a file myMonstersInclude.h like
#include "myMonster1.h"
#include "myMonster2.h"
....
Your main code will only need to do `#include "myMonstersInclude.h".
You could even generate it using your build tools, most allow you to run your own script before and after every step.
Short answer is: You can't.
Slightly longer is: You can create a header file that just #includes the other ones, and include the new header file in your .cpp files. This is still effectively including all the headers though, you just don't have the list of includes duplicated, which is why I said the shorts answer is you can't.
The new header would something like:
#include CMonster_cat
#include CMonster_puppy
...
The question is, does your map really need to know about all the individual types of monsters? Probably not - just knowing that they derive from CMonster should be enough as far as the map is concerned. All the methods that your map class uses should be able to operate through virtual functions on the monsters, so each monster type defines its specialized behavior, not the map.
I suspect your "include problem" will be greatly reduced by making proper use of inheritance here.
You could use a factory function. Combined with global static objects to register the types. Something like this:
// in some main file...
typedef CMonster*(*create_ptr)();
std::map<std::string, create_ptr> &get_map() {
// so we can make sure this exists...
// NOTE: we return a reference to this static object
static std::map<std::string, create_ptr> map;
return map;
}
we add some glue code to register a creation function...
// in each type of monster class (ex: CMonsterA)
CMonster *create_monster_a() {
return new CMonsterA;
}
static struct monsterA_Registrar {
monsterA_Registrar() {
get_map().insert(std::make_pair("MonsterA", create_monster_a));
}
} register_monsterA;
finally, back in the main file, you can create a monster object by the name of it's type...
std::map<std::string, create_ptr>::iterator it = get_map().find("MonsterA");
if(it != get_map().end()) {
return (it->second)();
}
throw "invalid monster type requested";
Here's what is happening:
When the program starts, before main, it will run all constructors of global objects, in this case register_monsterA is one of them.
This object's constructor will get get_map() (it can't just be a global static because we have no way of knowing what order things get initialized in if we do, so it's a function).
Then it will add an item to it which is a "creation function", basically a function which is capable of making a new CMonster.
Finally, to make a monster, we just look in that same map, and get the creation function and run it (if it was present).
EDIT: Here's a complete working example... (with some macro magic to make it cleaner)
CMonster.h
class CMonster {
public:
virtual ~CMonster() {
}
virtual void roar() = 0;
};
typedef CMonster*(*create_ptr)();
std::map<std::string, create_ptr> &get_map();
#define MONSTER_REGISTRAR(name) \
CMonster *create_monster_##name() { \
return new C##name; \
}\
\
static struct monster##name##_Registrar {\
monster##name##_Registrar() { \
get_map().insert(std::make_pair(#name, create_monster_##name));\
} \
} register_monster##name;
CMonster.cc
std::map<std::string, create_ptr> &get_map() {
// so we can make sure this exists...
// NOTE: we return a reference to this static object
static std::map<std::string, create_ptr> map;
return map;
}
CMonsterA.cc
#include "CMonster.h"
class CMonsterA : public CMonster {
public:
CMonsterA() {
std::cout << "HERE - A" << std::endl;
}
virtual void roar() {
std::cout << "A" << std::endl;
}
};
MONSTER_REGISTRAR(MonsterA)
CMonsterB.cc
#include "CMonster.h"
class CMonsterB : public CMonster {
public:
CMonsterB() {
std::cout << "HERE - B" << std::endl;
}
virtual void roar() {
std::cout << "B" << std::endl;
}
};
MONSTER_REGISTRAR(MonsterB)
main.cc
#include "CMonster.h"
CMonster *get_monster(const std::string &name) {
std::map<std::string, create_ptr>::iterator it = get_map().find(name);
if(it != get_map().end()) {
return (it->second)();
}
throw "invalid monster type requested";
}
int main() {
CMonster *monster = get_monster("MonsterB");
monster->roar();
delete monster;
}

How can I keep track of (enumerate) all classes that implement an interface

I have a situation where I have an interface that defines how a certain class behaves in order to fill a certain role in my program, but at this point in time I'm not 100% sure how many classes I will write to fill that role. However, at the same time, I know that I want the user to be able to select, from a GUI combo/list box, which concrete class implementing the interface that they want to use to fill a certain role. I want the GUI to be able to enumerate all available classes, but I would prefer not to have to go back and change old code whenever I decide to implement a new class to fill that role (which may be months from now)
Some things I've considered:
using an enumeration
Pros:
I know how to do it
Cons
I will have to update update the enumeration when I add a new class
ugly to iterate through
using some kind of static list object in the interface, and adding a new element from within the definition file of the implementing class
Pros:
Wont have to change old code
Cons:
Not even sure if this is possible
Not sure what kind of information to store so that a factory method can choose the proper constructor ( maybe a map between a string and a function pointer that returns a pointer to an object of the interface )
I'm guessing this is a problem (or similar to a problem) that more experienced programmers have probably come across before (and often), and there is probably a common solution to this kind of problem, which is almost certainly better than anything I'm capable of coming up with. So, how do I do it?
(P.S. I searched, but all I found was this, and it's not the same: How do I enumerate all items that implement a generic interface?. It appears he already knows how to solve the problem I'm trying to figure out.)
Edit: I renamed the title to "How can I keep track of... " rather than just "How can I enumerate..." because the original question sounded like I was more interested in examining the runtime environment, where as what I'm really interested in is compile-time book-keeping.
Create a singleton where you can register your classes with a pointer to a creator function.
In the cpp files of the concrete classes you register each class.
Something like this:
class Interface;
typedef boost::function<Interface* ()> Creator;
class InterfaceRegistration
{
typedef map<string, Creator> CreatorMap;
public:
InterfaceRegistration& instance() {
static InterfaceRegistration interfaceRegistration;
return interfaceRegistration;
}
bool registerInterface( const string& name, Creator creator )
{
return (m_interfaces[name] = creator);
}
list<string> names() const
{
list<string> nameList;
transform(
m_interfaces.begin(), m_interfaces.end(),
back_inserter(nameList)
select1st<CreatorMap>::value_type>() );
}
Interface* create(cosnt string& name ) const
{
const CreatorMap::const_iterator it
= m_interfaces.find(name);
if( it!=m_interfaces.end() && (*it) )
{
return (*it)();
}
// throw exception ...
return 0;
}
private:
CreatorMap m_interfaces;
};
// in your concrete classes cpp files
namespace {
bool registerClassX = InterfaceRegistration::instance("ClassX", boost::lambda::new_ptr<ClassX>() );
}
ClassX::ClassX() : Interface()
{
//....
}
// in your concrete class Y cpp files
namespace {
bool registerClassY = InterfaceRegistration::instance("ClassY", boost::lambda::new_ptr<ClassY>() );
}
ClassY::ClassY() : Interface()
{
//....
}
I vaguely remember doing something similar to this many years ago. Your option (2) is pretty much what I did. In that case it was a std::map of std::string to std::typeinfo. In each, .cpp file I registered the class like this:
static dummy = registerClass (typeid (MyNewClass));
registerClass takes a type_info object and simply returns true. You have to initialize a variable to ensure that registerClass is called during startup time. Simply calling registerClass in the global namespace is an error. And making dummy static allow you to reuse the name across compilation units without a name collision.
I referred to this article to implement a self-registering class factory similar to the one described in TimW's answer, but it has the nice trick of using a templated factory proxy class to handle the object registration. Well worth a look :)
Self-Registering Objects in C++ -> http://www.ddj.com/184410633
Edit
Here's the test app I did (tidied up a little ;):
object_factory.h
#include <string>
#include <vector>
// Forward declare the base object class
class Object;
// Interface that the factory uses to communicate with the object proxies
class IObjectProxy {
public:
virtual Object* CreateObject() = 0;
virtual std::string GetObjectInfo() = 0;
};
// Object factory, retrieves object info from the global proxy objects
class ObjectFactory {
public:
static ObjectFactory& Instance() {
static ObjectFactory instance;
return instance;
}
// proxies add themselves to the factory here
void AddObject(IObjectProxy* object) {
objects_.push_back(object);
}
size_t NumberOfObjects() {
return objects_.size();
}
Object* CreateObject(size_t index) {
return objects_[index]->CreateObject();
}
std::string GetObjectInfo(size_t index) {
return objects_[index]->GetObjectInfo();
}
private:
std::vector<IObjectProxy*> objects_;
};
// This is the factory proxy template class
template<typename T>
class ObjectProxy : public IObjectProxy {
public:
ObjectProxy() {
ObjectFactory::Instance().AddObject(this);
}
Object* CreateObject() {
return new T;
}
virtual std::string GetObjectInfo() {
return T::TalkToMe();
};
};
objects.h
#include <iostream>
#include "object_factory.h"
// Base object class
class Object {
public:
virtual ~Object() {}
};
class ClassA : public Object {
public:
ClassA() { std::cout << "ClassA Constructor" << std::endl; }
~ClassA() { std::cout << "ClassA Destructor" << std::endl; }
static std::string TalkToMe() { return "This is ClassA"; }
};
class ClassB : public Object {
public:
ClassB() { std::cout << "ClassB Constructor" << std::endl; }
~ClassB() { std::cout << "ClassB Destructor" << std::endl; }
static std::string TalkToMe() { return "This is ClassB"; }
};
objects.cpp
#include "objects.h"
// Objects get registered here
ObjectProxy<ClassA> gClassAProxy;
ObjectProxy<ClassB> gClassBProxy;
main.cpp
#include "objects.h"
int main (int argc, char * const argv[]) {
ObjectFactory& factory = ObjectFactory::Instance();
for (int i = 0; i < factory.NumberOfObjects(); ++i) {
std::cout << factory.GetObjectInfo(i) << std::endl;
Object* object = factory.CreateObject(i);
delete object;
}
return 0;
}
output:
This is ClassA
ClassA Constructor
ClassA Destructor
This is ClassB
ClassB Constructor
ClassB Destructor
If you're on Windows, and using C++/CLI, this becomes fairly easy. The .NET framework provides this capability via reflection, and it works very cleanly in managed code.
In native C++, this gets a little bit trickier, as there's no simple way to query the library or application for runtime information. There are many frameworks that provide this (just look for IoC, DI, or plugin frameworks), but the simplest means of doing it yourself is to have some form of configuration which a factory method can use to register themselves, and return an implementation of your specific base class. You'd just need to implement loading a DLL, and registering the factory method - once you have that, it's fairly easy.
Something you can consider is an object counter. This way you don't need to change every place you allocate but just implementation definition. It's an alternative to the factory solution. Consider pros/cons.
An elegant way to do that is to use the CRTP : Curiously recurring template pattern.
The main example is such a counter :)
This way you just have to add in your concrete class implementation :
class X; // your interface
class MyConcreteX : public counter<X>
{
// whatever
};
Of course, it is not applicable if you use external implementations you do not master.
EDIT:
To handle the exact problem you need to have a counter that count only the first instance.
my 2 cents
There is no way to query the subclasses of a class in (native) C++.
How do you create the instances? Consider using a Factory Method allowing you to iterate over all subclasses you are working with. When you create an instance like this, it won't be possible to forget adding a new subclass later.