Showing posts with label OOP. Show all posts
Showing posts with label OOP. Show all posts

Sunday, 23 April 2017

Strategy Pattern

Problem:

Context has to be able to apply different Algorithms (strategies, actions, behaviours) in the runtime but is coupled with their implementations. It contains all possible concrete implementations of an Algorithm family and has to change if:
  • implementation of some Algorithm has to change
  • a new Algorithm has to be added or some existing has to be removed
This breaks Single Responsibility Principle (Context has to change for more than one reason) and Open-Closed Principle (Context has to be modified if list of Algorithms gets extended).

Solution:

Remove Algorithm implementations out of the Context and separate them in their own classes which implement new interface IStrategy with method DoAlgorithm(). Introduce lookup table (Dictionary) which keeps all IStrategy implementations. When Context receives key from the input, it looks up the Dictionary and calls IStrategy implementation which matches the given key.

References:

Strategy pattern
Applying Strategy Pattern Instead of Using Switch Statements
Strategy

Monday, 16 April 2012

When does pure virtual destructor need its definition?

Deleting an instance of inherited class through a pointer to the base class yields memory leaks if destructor of the base class is not declared as virtual:

main.cpp:


Output:
main()
Parent::Parent()
Child::Child()
Child::foo()

Windows debugger output:
Detected memory leaks!
Dumping objects ->
{142} normal block at 0x00315588, 40 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

It is not enough just to declare base class as virtual, but we need to provide its definition as well (the one with empty body will suffice), otherwise linker will report error (if derived class' destructor is defined, implicitly or explicitly, as it calls base class destructor):

error LNK2001: unresolved external symbol "public: virtual __thiscall Parent::~Parent(void)" (??1Parent@@UAE@XZ)

Note that if our code didn't call (implicitly or explicitly) Child's destructor, and so Parent's one, linker would not complain. But in our case we have construction and destruction of Child object so Parent needs to have destructor defined:



Output (memory leaks are not reported anymore):
main()
Parent::Parent()
Child::Child()
Child::foo()
Child::~Child()
Parent::~Parent()

We are able to instantiate Parent class but if we want to prevent that but with keeping default implementation of foo(), we can declare its destructor as pure virtual function. But there is one interesting thing: although it is declared as pure virtual, we still need to provide implementation of destructor, otherwise linker will complain (if derived class' destructor is defined - which calls base class destructor)!

Parent as abstract base class:


Just to make this article complete, it is worth mentioning that if foo() wasn't declared as virtual in the base class, we would have needed to cast base class pointer to derived class pointer in order to invoke derived class' version of the function:



Output (no memory leaks):
main()
Parent::Parent()
Child::Child()
Parent::foo()
Child::foo()
Child::~Child()
Parent::~Parent()

Further reading:
(Im)pure Virtual Functions