c++ and IoC

V

Vladimir Jovic

Hello,

Following this :
http://www.codinginlondon.com/2009/05/cheap-ioc-in-native-c.html
I implemented an example of how I see IoC. This is just a naive attempt,
since the way the parameters are passed to the constructor is not very
good (at least in my opinion :) )

Can someone recommend a better way? A link to an example, or explanation
how it is done, would be best.

Here goes long example :


/// CODE
#include <string>
#include <map>
#include <iostream>
#include <typeinfo>
#include <cassert>
#include <memory>

class I
{
public:
I()
{
}
virtual ~I()
{
}

void foo()
{
doFoo();
}

private:
virtual void doFoo() = 0;
};

class A : public I
{
public:
A( const int v_) : I(),
v( v_ )
{
std::cout<<"A::A() v="<<v<<std::endl;
}
virtual ~A()
{
std::cout<<"A::~A()"<<std::endl;
}

static void setParams( const int nextParam )
{
newCreateParam = nextParam;
}
static I* create()
{
return new A( newCreateParam );
}

private:
virtual void doFoo()
{
std::cout<<"A::doFoo() v="<<v<<std::endl;
}

int v;

static int newCreateParam;
};
int A::newCreateParam=0;

class B : public I
{
public:
B() : I()
{
std::cout<<"B::B()"<<std::endl;
}
virtual ~B()
{
std::cout<<"B::~B()"<<std::endl;
}

static I* create()
{
return new B;
}

private:
virtual void doFoo()
{
std::cout<<"B::doFoo()"<<std::endl;
}
};

std::map< std::string, I* (*)() > GetCreator()
{
std::map< std::string, I* (*)() > m;

m[ typeid(A).name() ] = &A::create;
m[ typeid(B).name() ] = &B::create;

return m;
}
const std::map< std::string, I* (*)() > creator = GetCreator();

I* CreateObj( const std::string whichOne )
{
std::cout<<"Creating new object of type = " << whichOne << std::endl;

for ( std::map< std::string, I* (*)() >::const_iterator it =
creator.begin(); creator.end() != it; ++ it )
{
if ( std::string::npos != it->first.find( whichOne ) )
{
I* (*func)() = it->second;
return func();
}
}

std::cout<<"The creator for the class " << whichOne << " not
found." << std::endl;

return NULL;
}

int main()
{
A::setParams( 55 );

std::auto_ptr< I > newObj1( CreateObj( "B" ) );
std::auto_ptr< I > newObj2( CreateObj( "A" ) );
std::auto_ptr< I > newObj3( CreateObj( "C" ) );

if ( NULL != newObj1.get() )
{
newObj1->foo();
}
if ( NULL != newObj2.get() )
{
newObj2->foo();
}
if ( NULL != newObj3.get() )
{
newObj3->foo();
}
}

/// END OF CODE
 
M

Michael Doubez

Hello,

Following this :http://www.codinginlondon.com/2009/05/cheap-ioc-in-native-c.html
I implemented an example of how I see IoC. This is just a naive attempt,
since the way the parameters are passed to the constructor is not very
good (at least in my opinion :) )

Can someone recommend a better way? A link to an example, or explanation
how it is done, would be best.
[snip]

AFAIS you have not done a IoC but a simple factory. The principle of
IoC is that you register a *single* builder of a concrete
implementation of an interface.
In the article, it is a map typeid->builder but it is misleading
because, the register function is:

template<class T> static void Register(const T& object)
{
typeInstanceMap[typeid(T).name()] = (void*)&object;
}

and it is supposed to be called with explicit specialization:
Resolver::Register<IDataLayer>(dataLayer);

But if you forget to specialize:
Resolver::Register(dataLayer);

You won't be able to retreive you object because the map will be
filled with typeid(FakeDataLayer) and not typeid(IDataLayer).

Well, even the article's implementation is not portable because there
is no guarantee regarding typeid().name() - it could be empty for all
types.
 
M

Michael Doubez

Hello,

Following this :http://www.codinginlondon.com/2009/05/cheap-ioc-in-native-c.html
I implemented an example of how I see IoC. This is just a naive attempt,
since the way the parameters are passed to the constructor is not very
good (at least in my opinion :) )

Can someone recommend a better way? A link to an example, or explanation
how it is done, would be best.

The first step is to get an exploitable typeid information. IIRC
Andrei Alexandrescu gives an implementation in Modern C++; it uses a
TypeInfo wrapper storing a pointer on std::type_info and defining a
strict ordering on the member "before" (which defines a global
ordering).

One you have that, you can define a map of typeinfo to a builder
pattern.

For, the way to register/recover an implementation (like in the
article, I would use a proxy object to ensure type compatibility and
type safety.

Something like:
class IoCBuilderBase
{
virtual ~IoCBuilderBase(){}
};

template<class T>
struct IoCBuilder: IoCBuilderBase
{
virtual T* build(/* parameters */) = 0;
};


struct IoC
{

static std::map<TypeInfo,IoCBuilderBase*> _builders;

template<class T>
struct Interface
{
static void registerBuilder(T* (*builder)() )
{
// allocate type inherithing IoCBuilder<IoCBuilder>
IoC::_builders[TypeInfo(typeid(T))]=ptr;
}

// other registration with fonctor ...

static T* create()
{
IoCBuilderBase* ptr = // get base with TypeInfo(typeid(T))
IoCBuilder<IoCBuilder>* builder = dynamic_cast<
IoCBuilder<IoCBuilder>* >(ptr);
assert( builder )
return builder->build();
}
};
};

That way, in you example, you write

IoC::Interface<I>::registerBuilder(&A::create);
I* i = IoC::Interface<I>::create();
assert( dynamic_cast<A*>(i) );

IoC::Interface<I>::registerBuilder(&B::create);
i = IoC::Interface<I>::create();
assert( dynamic_cast<B*>(i) );
 
V

Vladimir Jovic

Michael said:
Hello,

Following this :http://www.codinginlondon.com/2009/05/cheap-ioc-in-native-c.html
I implemented an example of how I see IoC. This is just a naive attempt,
since the way the parameters are passed to the constructor is not very
good (at least in my opinion :) )

Can someone recommend a better way? A link to an example, or explanation
how it is done, would be best.
[snip]

AFAIS you have not done a IoC but a simple factory.

Yes, you are right. I realized after reading your post :(
The principle of
IoC is that you register a *single* builder of a concrete
implementation of an interface.
In the article, it is a map typeid->builder but it is misleading
because, the register function is:

template<class T> static void Register(const T& object)
{
typeInstanceMap[typeid(T).name()] = (void*)&object;
}

and it is supposed to be called with explicit specialization:
Resolver::Register<IDataLayer>(dataLayer);

But if you forget to specialize:
Resolver::Register(dataLayer);

You won't be able to retreive you object because the map will be
filled with typeid(FakeDataLayer) and not typeid(IDataLayer).

What mostly confuses me about IoC is this : you create an object of a
certain type (which inherits from an interface), then you put it in some
container (map seams to be the best). Something like :

struct I
{
virtual ~I() {};
};
struct A : public I
{
};
A theInstanceOfA;

It is not possible to create more instances of A.

Did I get all this right so far?

Well, even the article's implementation is not portable because there
is no guarantee regarding typeid().name() - it could be empty for all
types.

I know, but lets assume the typeid works fine.
 
V

Vladimir Jovic

Vladimir said:
Michael said:
Hello,

Following this
:http://www.codinginlondon.com/2009/05/cheap-ioc-in-native-c.html
I implemented an example of how I see IoC. This is just a naive attempt,
since the way the parameters are passed to the constructor is not very
good (at least in my opinion :) )

Can someone recommend a better way? A link to an example, or explanation
how it is done, would be best.
[snip]

AFAIS you have not done a IoC but a simple factory.

Yes, you are right. I realized after reading your post :(
The principle of
IoC is that you register a *single* builder of a concrete
implementation of an interface.
In the article, it is a map typeid->builder but it is misleading
because, the register function is:

template<class T> static void Register(const T& object)
{
typeInstanceMap[typeid(T).name()] = (void*)&object;
}

and it is supposed to be called with explicit specialization:
Resolver::Register<IDataLayer>(dataLayer);

But if you forget to specialize:
Resolver::Register(dataLayer);

You won't be able to retreive you object because the map will be
filled with typeid(FakeDataLayer) and not typeid(IDataLayer).

What mostly confuses me about IoC is this : you create an object of a
certain type (which inherits from an interface), then you put it in some
container (map seams to be the best). Something like :

struct I
{
virtual ~I() {};
};
struct A : public I
{
};
A theInstanceOfA;

It is not possible to create more instances of A.

Did I get all this right so far?

Never mind this nonsense. I missed the keyword "builder"
The other thread explains everything nicely. Thank you
 
M

Michael Doubez

Vladimir said:
Michael said:
Hello,
Following this
:http://www.codinginlondon.com/2009/05/cheap-ioc-in-native-c.html
I implemented an example of how I see IoC. This is just a naive attempt,
since the way the parameters are passed to the constructor is not very
good (at least in my opinion :) )
Can someone recommend a better way? A link to an example, or explanation
how it is done, would be best.
[snip]
AFAIS you have not done a IoC but a simple factory.
Yes, you are right. I realized after reading your post :(
 The principle of
IoC is that you register a *single* builder of a concrete
implementation of an interface.
In the article, it is a map typeid->builder but it is misleading
because, the register function is:
    template<class T> static void Register(const T& object)
    {
        typeInstanceMap[typeid(T).name()] = (void*)&object;
    }
and it is supposed to be called with explicit specialization:
Resolver::Register<IDataLayer>(dataLayer);
But if you forget to specialize:
Resolver::Register(dataLayer);
You won't be able to retreive you object because the map will be
filled with typeid(FakeDataLayer) and not typeid(IDataLayer).
What mostly confuses me about IoC is this : you create an object of a
certain type (which inherits from an interface), then you put it in some
container (map seams to be the best). Something like :
struct I
{
 virtual ~I() {};
};
struct A : public I
{
};
A theInstanceOfA;
It is not possible to create more instances of A.
Did I get all this right so far?

Never mind this nonsense. I missed the keyword "builder"
The other thread explains everything nicely. Thank you

Well, it depends on what your facade is supposed to do, if it is
supposed to connect components and/or instantiate them. I have made it
a builder in order to follow your example

IMHO the general case of IoC returns a single instance and you can
make it return an instance of an (abstract) factory to generate your
objects.
 
A

Alf P. Steinbach /Usenet

* Michael Doubez, on 03.08.2010 12:55:
The first step is to get an exploitable typeid information. IIRC
Andrei Alexandrescu gives an implementation in Modern C++; it uses a
TypeInfo wrapper storing a pointer on std::type_info and defining a
strict ordering on the member "before" (which defines a global
ordering).

There's also one on my blog (mentioning Andrei's, of course), plus one in the
C++0x standard library. :)


Cheers,

- Alf
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,990
Messages
2,570,211
Members
46,796
Latest member
SteveBreed

Latest Threads

Top