Sign in to follow this  
RyanZec

Problem Creating an "Interface"

Recommended Posts

RyanZec    124
I am not 100% if this is teh right way of using a word interface so please create me if I am wrong. I am reading the book Head First Design Patterns and trying to follow along with their examples which are written in Java(I am working in C++). This first one is basically we have a base class of Duck, here is the code for it:
#include "fly_behavior.h"
#include "speak_behavior.h"

#ifndef DUCK_H
#define DUCK_H

abstract class Duck
{
public:
	Duck();
	~Duck();
	void PerformFly();
	void PerformSpeak();

protected:
	FlyBehavior * _fly_behavior;
	SpeakBehavior * _speak_behavior;
};

#endif

#include "duck.h"

Duck::Duck()
{

}

Duck::~Duck()
{

}

void Duck::PerformFly()
{
	this->_fly_behavior->Fly();
}

void Duck::PerformSpeak()
{
	this->_speak_behavior->Speak();
}

Know the 2 "interfaces" i have hear is the FlyBehavior class and SpeakBehavior class, here is the code for those:
#ifndef FLY_BEHAVIOR_H
#define FLY_BEHAVIOR_H

class FlyBehavior
{
public:
	void Fly();
};

#endif

#include "fly_behavior.h"

void FlyBehavior::Fly()
{

}


#ifndef SPEAK_BEHAVIOR_H
#define SPEAK_BEHAVIOR_H

class SpeakBehavior
{
public:
	void Speak();
};

#endif

#include "speak_behavior.h"

void SpeakBehavior::Speak()
{

}

Now the reason that the methods in these classes and blank is becuase I should never have to have an object typ eof this class, only objects that are sub classes. from my understanding, which is rusty since i havr been mainly doing PHP code for the past 1 1/2 and not c++, is that if Squeak class is a sub class of SpeakBehavior that to following sode would work:
SpeakBehavior * _speak_behavior = new Squeak()

THis code does work for my ToyDuck class that is a sub class of duck, here is that code:
#include "duck.h"

#ifndef TOY_DUCK_H
#define TOY_DUCK_H

class ToyDuck: public Duck
{
public:
	ToyDuck();
	~ToyDuck();
};

#endif

#include "toy_duck.h"
#include "not_fly.h"
#include "squeak.h"

ToyDuck::ToyDuck()
{
	this->_fly_behavior = new NotFly();
	this->_speak_behavior = new Squeak();
}

ToyDuck::~ToyDuck()
{

}

This code sompiles fine but when i run it and do
#include <iostream>
#include <conio.h>

#include "toy_duck.h"

void main()
{
	std::cout << "DUCK SIMULATOR" << std::endl;
	
	ToyDuck * toy_duck_object = new ToyDuck();

	toy_duck_object->PerformFly();
	toy_duck_object->PerformSpeak();
	
	_getch();
}

the PerformFly and PerformSpeak run the Fly/Speak method from the FlyBehavior and SpeakBehavior and not the NotFly or Squeak, which a sub classes of FlyBehavior and SpeakBehavior, even tho NotFly or Squeak have thier own Fly/Speak methods defined. Can anyone see why these classes are running the superclasses methods and the the child classes methods?

Share this post


Link to post
Share on other sites
Barius    325
In C++, if you want the correct subclass method to be called when working with a base class pointer, you need to declare the method as "virtual" in the base class.

Also, if you allocate objects with "new" in a constructor, you should delete them in the destructor of the class.

Share this post


Link to post
Share on other sites
RyanZec    124
When I declare those function virtual is the base class i get a linking error becuase I don't greate the defination for those function but i should not have to since they are virtual.

Oh an dthnaks for pointing out the memory leak, thanks.

Share this post


Link to post
Share on other sites
darookie    1441

#include "fly_behavior.h"
#include "speak_behavior.h"

#ifndef DUCK_H
#define DUCK_H

// "Duck" is not abstract
class Duck
{
public:
// pass the behavior in the ctor - favour composition over inheritance
Duck(FlyBehavior *, SpeakBehavior*);
~Duck();
void PerformFly();
void PerformSpeak();

protected:
FlyBehavior * _fly_behavior;
SpeakBehavior * _speak_behavior;
};

#endif




#include "duck.h"

// use proper constructor initialisers
Duck::Duck(FlyBehavior * fly, SpeakBehavior * speak)
: _fly_behavior(fly),
_speak_behavior(speak)
{
}

// remember to delete what you allocate
Duck::~Duck()
{
delete _fly_behavior;
delete _speak_behavior;
}

void Duck::PerformFly()
{
_fly_behavior->Fly();
}

void Duck::PerformSpeak()
{
_speak_behavior->Speak();
}




#include "duck.h"
#include "not_fly.h"
#include "squeak.h"

namespace
{
Duck * MakeToyDuck()
{
return new Duck(new NoFly, new Squeak);
}
}

// "main" should return "int"
int main()
{
std::cout << "DUCK SIMULATOR" << std::endl;

// prefer a factory method over inheritance
Duck * toy_duck_object = MakeToyDuck();

toy_duck_object->PerformFly();
toy_duck_object->PerformSpeak();

delete toy_duck_object;
}




The above doesn't reflect your idea of the design, but illustrates the intention. Compare it to the implementation that uses inheritance, which is is given below:


#ifndef DUCK_H
#define DUCK_H

// "Duck" is an abstract base class
class Duck
{
public:
// note the virtual destructor
virtual ~Duck();

void PerformFly();
void PerformSpeak();

protected:
// make the ctor protected, i.e. "Duck" cannot be instanciated
Duck(FlyBehavior *, SpeakBehavior *);

FlyBehavior * _fly_behavior;
SpeakBehavior * _speak_behavior;
};

#endif



#include "duck.h"

Duck::Duck(FlyBehavior * fly, SpeakBehavior * speak)
: _fly_behavior(fly),
_speak_behavior(speak)
{
}

Duck::~Duck()
{
delete _fly_behavior;
delete _speak_behavior;
}

void Duck::PerformFly()
{
_fly_behavior->Fly();
}

void Duck::PerformSpeak()
{
_speak_behavior->Speak();
}




include "duck.h"

#ifndef TOY_DUCK_H
#define TOY_DUCK_H

// the dtor is not necessary, it's already defined in "Duck"
class ToyDuck: public Duck
{
public:
// the ctor is public and omits the behavior arguments
ToyDuck();
};

#endif




#include "toy_duck.h"
#include "not_fly.h"
#include "squeak.h"

// the ctor invokes the base class' ctor with the appropriate arguments
ToyDuck::ToyDuck() : Duck(new NotFly, new Squeak)
{
}





#include <iostream>

#include "toy_duck.h"

// "main" stays the same
int main()
{
std::cout << "DUCK SIMULATOR" << std::endl;

// note that you can use both "Duck" and "ToyDuck" as your
/ object's type. prefer the base class.
Duck * toy_duck_object = new ToyDuck;

toy_duck_object->PerformFly();
toy_duck_object->PerformSpeak();

delete toy_duck_object;
}




Finally, your behavior "interfaces" are no real interfaces. Interfaces in C++ should be abstract classes:


#ifndef FLY_BEHAVIOR_H
#define FLY_BEHAVIOR_H

class FlyBehavior
{
public:
// the "virtual" is required so that calls to the interface
// will dispatch to the derived class. the " = 0" denotes
// an abstract method, i.e. FlyBehavior::Fly() cannot be called
// and FlyBehavoir cannot be instanciated.

// the brackets are the default implementaion, which may be called
// by derived classes using "FlyBehavior::Fly()"
virtual void Fly() = 0 { }
};

/*
Example:

class NoFly : public FlyBehavior
{
// implement "Fly" by just calling the default implementation.
// only works if a default implementation exists, though.
void Fly()
{
FlyBehavior::Fly();
}
};
*/


#endif



The same principle applies to "SpeakBehavior". The reason your derived classes didn't work was the fact that the behavoir "interface" methods weren't marked "virtual".

Hope that clears things up a little,
Pat

PS: No guarantees, though - I didn't work with C++ for quite some time [smile]
PPS: Seems I'm a bit slow [lol]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this