views:

513

answers:

3

How do I implement dependancy injection in C++ explicitly without using frameworks or reflection?

I could use a factory to return a auto_ptr or a shared_ptr. Is this a good way to do it?

+1  A: 

AFAIK dependency injection just means, that there is an interface to an component needed by another one.

namespace ifc {
  struct service { 
    virtual ~service() {}
    virtual do_stuff(/*..*/) = 0;  
  };
} // ns ifc

class ServiceProviderA : public ifc::service 
{ 
public;
  do_stuff(/*..*/) { /*...*/ }
};

class ServiceProviderB : public ifc::service {/*...*/};

class Client
{
public;
  client(ifc::service*);
private:
  ifc::service* m_service;
};

I can only guess, but is your question how to manage the lifetime of the injected Object?

Maik Beckmann
Your code is very near to the problem. And yes the question is about how to manage the lifetime of injected objects.
frast
+2  A: 

Just use a shared_ptr to the service you need, and make a setter to it. E.g.:

class Engine;

class Car {
public:
    void setEngine(shared_ptr<Engine> p_engine) {
        this->m_engine = p_engine;
    }

    int onAcceleratorPedalStep(int p_gas_pedal_pressure) {
        this->m_engine->setFuelValveIntake(p_gas_pedal_pressure);
        int torque = this->m_engine->getTorque();
        int speed = ... //math to get the car speed from the engine torque
        return speed;
    }

protected:
    shared_ptr<Engine> m_engine;
}

// (now must create an engine and use setEngine when constructing a Car on a factory)

Avoid using auto_ptr, because you can't share it through more than one object (it transfers ownership when assigning).

e.tadeu
This sounds very reasonable. Is it ok to do this just to make the code testable or are there better alternatives?
frast
It's ok, you won't lose too much performance, and your code will be much more flexible and testable!
e.tadeu
A: 

How about assuming the ownership of the injected object transfers to the dependent object. This will solve the lifetime problem for composition avoiding usage of smart pointers. But, for complex situations where ownership matters smart pointers will be the choice.

class Car {
    public:
      Car(IEngine *pEngine) {
        m_pEngine = pEngine;
      }

      ...

      ~Car()
      {
         delete m_engine;
      }

    protected:
      IEngine *m_pEngine;
    }

For the cases where dependet is sure to have less lifetime than the injected object, its better to pass injected object as a reference. This will clearly indicate that the injected object is not owned by the dependet object.

Varuna