Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I have seen a lot of advice that it is better to do Type object; than

Type* object = new Type();

in C++ whenever possible—i.e., minimize your use of new. I understand the rational behind this and appreciate it.

But according to my understanding, to practice dependency inversion requires pointers, e.g.:

Type* object = new Implementation();

where Type is abstract (i.e. contains at least one pure virtual method) and Implementation is concrete. It is not possible to do

Type object = Implementation();

because what that means is

Type object;
object = Implementation();

which requires constructing object as a Type initially—but that cannot be done, since Type is abstract.

Is there an inherent tension between the dependency inversion principle and avoiding new when using C++? If so, what patterns/principles/practices can be used to mitigate this tension?

share|improve this question
3  
Python is my mother tongue; memory management is a language feature from another continent. ;) –  Kazark Nov 27 '12 at 20:44
1  
I know the feeling. What you're saying doesn't make sense to me though because to me the Dependency Inversion Principle is about relying on abstracts not concretions which regards use of interfaces/abstract classes/contracts in whichever form your language supports them. I don't know C++ but I'm not inclinced to think a pointer to a class makes it an "abstraction" so much as it makes it a reference which might be shared. –  Jimmy Hoffa Nov 27 '12 at 20:51
    
@JimmyHoffa I am no C++ guru (yet--working on it little by little), but here's my understanding. The only way I know of to do it without a pointer is Type object = Implementation(). Counterintuitively, C++ tries to create an object of type Type, assigns it to object, creates an anonymous object of type Implementation, and calls object's copy constructor on it. This fails if Type is abstract, however. That is why I do not know a way around pointers. I certainly see why this doesn't make sense to you, though! –  Kazark Nov 28 '12 at 1:38
add comment

3 Answers

up vote 7 down vote accepted

You can absolutely use Dependency Injection without ever using new(). Polymorphism, which is what you're talking about here, is realized in C++ using pointers and/or references. Doc Brown already addressed references, let's talk about pointers.

As an example (assuming that Implementation is derived from Type, and Bar's constructor takes a pointer to a Type):

Implementation imp;
Bar bar(&imp);

The "address of" operator (&) takes the address of an object, the result is a pointer to the object. This is a different way of getting a pointer to an object (different compared to your use of new, that is.)

In C++, any time I have a pointer to a Derived, I can also use it as a pointer to a Base. That's the whole idea of polymorphism, a Derived is a Base, right?

If my 2-step example above made a leap that you couldn't follow, I'll repeat it here, but with one more (unnecessary) step:

Implementation imp;
Type *t = &imp;
Bar bar(t);

t is a pointer to a Type, so it can point to any class derived from Type, including Implementation. No use of new. No tension.

share|improve this answer
    
+1 for getting it right that "dependency inversion" was only a red herring and the real question was only "how do pointers work in C++" –  Doc Brown Nov 28 '12 at 16:30
1  
@DocBrown But what about the factory method pattern? That is a stock way of performing dependency injection, useful for creating fakes for testing, such as you discussed in your answer. Returning a reference to an object allocated on the stack is unsafe, so is that not an example in which new must be employed for proper dependency inversion? I really wasn't asking about how pointers work, though an elucidation of that has been helpful. It still seems there is some tension between avoid new and DIP. –  Kazark Nov 28 '12 at 18:22
1  
@Kazark: The method described here can (AIUI) only be used to inject dependencies down the stack. But that actually fits the typical pattern of dependency injection, where some top level code makes decisions about what objects to construct, and then injects them into each other. –  Tom Anderson Nov 28 '12 at 18:53
1  
It can be used to create a sort of factory pattern if the alleged factory just returns a pointer to an object which was created earlier by the top level code. So, less of a factory and more of a warehouse, as the top level is creating it, then leaving it there. –  Tom Anderson Nov 28 '12 at 18:53
    
I'm getting a warning something like warning: taking address of local variable. I found I could get around this like this: const Type& t = Implementation(); Bar bar((Type*)&t), but that is very messy compared to Type* t = new Implementation(); Bar bar(t); delete t. I also do not want to be getting any compiler warnings. It's still looks like there is a tension between "avoid new" and the DIP, and I'm inclined to fudge on the "avoid new" rather than the DIP. –  Kazark Dec 4 '12 at 1:01
add comment

No, dependency inversion does not necessitate pointers.

The decision to use pointers or not is a question of data sharing and memory optimization.

Dependency inversion has to do with class hierarchies and inhertiance.

All the same places where you expect to pass Type* that was allocated with new Type() can be changed to accept a Type& that is created with type = Type().

share|improve this answer
    
Ah yes, but what about when I am expected to pass Type* and it was allocated with new Implementation()? That's what I'm asking. If Type is abstract, Type object = Implementation() fails. –  Kazark Nov 28 '12 at 1:40
    
Okay, my apologies. I see that I didn't make it very clear that I meant Type to be abstract in the question. I have now clarified that in the question. –  Kazark Nov 28 '12 at 6:09
1  
@Kazark: It works you just need a reference. Type& object = Implementation(); –  Loki Astari Nov 28 '12 at 19:17
    
@LokiAstari It seems that doesn't work, but rather: const Type& object = Implementation();. I couldn't get it to compile without the const, anyway. The sad thing is that then, when I go to use it, I have to cast away the const, thus: (Type*)&object. The result is very messy. –  Kazark Dec 4 '12 at 1:05
    
@Kazark: That's probably because you returned by value. If you return by reference then no need for the const. Depending on your code returning by value is probably wrong as it would cause object slicing. –  Loki Astari Dec 4 '12 at 4:35
show 4 more comments

DIP means instead of instantiating objects of class Foo directly in class Bar, you have an abstract interface IFoo, and pass already constructed objects of type IFoo into Bar (for example, through the constructor of Bar). That allows you easily to replace Foo objects in Bar by MockFoo objects for example, for testing purposes. If those objects are constructed on the stack like

 Foo foo;
 Bar bar(&foo);

or dynamically like

 IFoo *foo = new Foo();
 Bar bar(foo);

where Bar constructor has the signature

  Bar(IFoo *foo)
  {
       //...
  }

does not matter in terms of DIP, that decision does only depend on the intended life time of your object foo (which in both cases should be at least as long as the lifetime of bar).

The pointer variant is technically different on one aspect: if you like, you can transfer the ownership of the foo object to bar and let bar do the memory cleanup by calling delete on fooin the destructor. However, it is questionable if this is good programming style, and I would not recommend that technique to you. If you want to have automatic cleanup of foo when bar does not need it any more, I suggest that you better make use of smart pointers.

To your edit: I guess you have a misconception here about pointers and "new". This code

 Implementation object;
 Type *ptrObject = &object;

gives you a pointer to an object of type Type without using new. Or in short:

"Avoiding the usage of new" != "You cannot have pointers"

(and both is irrelevant to the dependency inversion principle).

share|improve this answer
    
@Kazark: my first two code lines in the DIP example above don't use new, didn't you notice? See my edit. –  Doc Brown Nov 28 '12 at 14:34
    
Okay, I did, but I didn't follow that you were actually still using dependency inversion—sorry. Thanks! +1 –  Kazark Nov 28 '12 at 15:02
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.