Problems with pure virtual and Factory Method

Hi guys!

I am getting the error:

SniperFactory.cpp: In member function ‘virtual Survivor* SniperFactory::createSurvivor(std::string)’:
SniperFactory.cpp:7:39: error: cannot allocate an object of abstract type ‘Survivor’
Survivor.h:9:7: note: because the following virtual functions are pure within ‘Survivor’:
Survivor.h:32:15: note: virtual bool Survivor::hitZombie(Zombie*)
Survivor.h:33:15: note: virtual void Survivor::celebrate()
Survivor.h:34:15: note: virtual bool Survivor::getHit(Zombie*)
Survivor.h:35:15: note: virtual void Survivor::die()

Here is my code:

My code is organised here as follows: (1) the relevant statements from main.cpp, (2) a base factory class (as I have a few factory subclasses), (3) my SniperFactory class (only showing this subclass in this post), (4) a Survivor class (which holds a survivor's member variables and then (5) my SniperFactory.cpp (implementation of the SniperFactory Class)...

(1) In main I have the following calls and instantiations:
1
2
SurvivorFactory* sniperFactory = new SniperFactory();
Survivor* sniper = sniperFactory->createSurvivor("Roger");


(2) The base factory class, from which SniperFactory inherits:
1
2
3
4
5
6
7
8
9
class SurvivorFactory
{	
    public:
	SurvivorFactory() {}
	virtual ~SurvivorFactory() {}
	
	virtual Survivor* createSurvivor(string);

};


(3) The SniperFactory Class:
1
2
3
4
5
6
7
8
class SniperFactory : public SurvivorFactory
{	
public:
	SniperFactory() {}
	~SniperFactory() {}
	
	Survivor* createSurvivor(string);
};


(4) The Survivor class: (Note I created and implemented all the setters(implementation not shown here) so that the SniperFactory implementation can edit the Survivor member variables)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Survivor
{
protected:
    string name;
	int hp;
	string primaryWeapon;
	string secondaryWeapon;
	int damage;
	
public:
	// constructs a survivor with the specified name
    Survivor(string);
	~Survivor();
	
	void attack(Zombie*);
	
	virtual bool hitZombie(Zombie*) = 0; //These functions are implemented and work
	virtual void celebrate() = 0;   //don't worry about what they do
	virtual bool getHit(Zombie*) = 0;
	virtual void die() = 0;
	
	void setName(string);
	void setPrimary(string);
	void setSecondary(string);
	void setHP(int);
	void setDamage(int);
};


Now here is my problem: I have to return a pointer to a Survivor, but I cannot say something such as "Survivor *sniper = new Survivor(name);" - as I currently do in my code. This is because there are pure virtual functions in the Survivor class. How can I work around this as I need to return a pointer to a Survivor to return a Survivor(created by the Sniper Factory) to where the Survivor is instantiated in main.

(5) Here is my implementation of the SniperFactory Class:
1
2
3
4
5
6
7
8
9
10
11
12
13
Survivor* SniperFactory::createSurvivor(string name)
{
	Survivor *sniper =  new Survivor(name); //this is resulting in the error
	
	sniper->setName(name);
  	sniper->setPrimary(".308 Rifle");
	sniper->setSecondary("Binoculars");
	sniper->setHP(6);
	sniper->setDamage(5);

	return sniper;
	
}


Help in this matter will be greatly appreciated!!

P.S Please also indicate if this is the right approach (to use setters to change the member variables of the Survivor class) to create a new survivor (I have to do it through a factory).

Thanks!
Last edited on
You have to create a derived class and implement the pure virtual functions. You can have several of them and then you can choose the actual instantiated object based, for example, on the name. This is actually what are factories for: localize the knowledge about all the subclasses in only one class - the factory, while other classes use these objects via a common interface without even knowing about them. Does that help?

Also, this code makes no sense:
1
2
3
	return sniper;
	sniper = 0;
	delete sniper;

When you write a return statement - the function exits immediately, so the code after a return is not executed.
Also you try to delete an object you have just returned - this is conceptually wrong - the user of the factory will try to access the object that is already deleted. You should either let the user care about deleting the object, or make a function destroySurvivor() in your factory, or, even better, use smart pointers, such as std::shared_ptr.
Last edited on
One more thing - if you have virtual functions in your class - make the destructor also virtual, because the objects you create are likely to be deleted via a pointer to base class which will lead to a call to a wrong destructor if it is not declared virtual.
Hi KRAkatau! Thanks for the reply! This is the first time I have ever worked with inheritance and polymorphism - so please go easy on me :P

You say: "You have to create a derived class and implement the pure virtual functions."

I have derived classes where I implement these following 4 functions fully. (I have also tested them before I started with the factory method - and they work):
1
2
3
4
        virtual bool hitZombie(Zombie*) = 0; 
	virtual void celebrate() = 0;   
	virtual bool getHit(Zombie*) = 0;
	virtual void die() = 0;


And in the Factory Method, my derived class is SniperFactory: (The implementation of my SniperFactory class is also where I implement the pure virtual "createSurvivor" function):
1
2
3
4
5
6
7
8
class SniperFactory : public SurvivorFactory
{	
public:
	SniperFactory() {}
	~SniperFactory() {}
	
	Survivor* createSurvivor(string);
};]


and the base class is SurvivorFactory:
1
2
3
4
5
6
7
8
9
class SurvivorFactory
{	
    public:
	SurvivorFactory() {}
	virtual ~SurvivorFactory() {}
	
	virtual Survivor* createSurvivor(string);

};


My implementation of the Derived class's pure virtual then:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Survivor* SniperFactory::createSurvivor(string name)
{
	Survivor *sniper =  new Survivor(name); //this is resulting in the error
	
	sniper->setName(name);
  	sniper->setPrimary(".308 Rifle");
	sniper->setSecondary("Binoculars");
	sniper->setHP(6);
	sniper->setDamage(5);

	return sniper;

	
}


Is there anything else that I have to do when it comes to implementing the virtual functions?

My problem relates to the errors I am getting:

I do not fully understand how I can create a pointer to a Survivor object if I cannot instantiate a Survivor object in the SniperFactory? Will multiple inheritance help in any way? (The factories are not inheriting from the Survivor class at this moment)

My main question is thus: how do I create pointer to an object without causing the errors that are currently being cause by the fact that some of my functions are pure virtual in the Survivor class? The way that I am currently trying --> "Survivor *sniper = new Survivor(name);" only results in errors.

Also, thanks for the comments on the code that makes no sense - your advice has been heeded :) I have also made the destructors virtual where I have virtual functions in my class :)
Last edited on
Ok. Let's go step by step.

1) You can convert a pointer to a derived class to a pointer to a base class (it is always safe). For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Base {
public:
   virtual int f() { return 1; } 
};

class Derived : public Base {
public:
   virtual int f() { return 2;}
};

int main()
{
    Base* basePtr;
    Derived derived;

    basePtr = &derived; // this is valid
}

More on this topic here: http://www.cplusplus.com/doc/tutorial/polymorphism/

So you should create a derived class of a Survivor (the one where these pure virtual functions are implemented). For example, you could have your factory method done this way:

1
2
3
4
5
6
7
8
9
10
11
12
Survivor* SniperFactory::createSurvivor(string name) // note that it still returns Survivor*
{
	Sniper *sniper =  new Sniper(name); 

	sniper->setName(name);
  	sniper->setPrimary(".308 Rifle");
	sniper->setSecondary("Binoculars");
	sniper->setHP(6);
	sniper->setDamage(5);

	return sniper;
}

This will work if you have a class Sniper that is derived from Survivor, which implements all the pure virtual functions.

Now, on factories. I wouldn't do it the way you do it now. If you want to create different types of survivors you don't need a separate factory class for every survivor class. It will not help you to reduce the amount of knowledge you need to create a certain type of survivor. If your factories can only create one type of survivors and all they do is set up their parameters - you can do it differently and less wordy. For example, the parameters you set may be initialized in a constructor.

However, if you want some part of your code to be isolated from knowing anything about survivor subclasses, or you would like adding a new survivor type to be easy - you can do a factory this way:


1
2
3
4
5
6
7
8
9
10
11
12
13
class SurvivorFactory {	
public:
   Survivor* createSurvivor(const std::string& survivorType, const std::string& playerName)
   {
      if (survivorType == "sniper") {
         return new Sniper(playerName);
      } 
      if (survivorType == "bomber") {
         return new Bomber(playerName);
      }
      return nullptr; // or signify the problem in another way, such as throwing an exception
   } 
};


So, when you have a new type of survivor - all you need to do is to change this method (which of course should be in a .cpp - I put it in header just for brevity). And the code that uses this factory doesn't need to change at all to be able to work with this new type of survor (for example, the names for types of characters may be read from file). That's kind of the idea behind a factory class.

If anything is unclear or you have some other questions - feel free to ask :)
KRAkatau!

Thank you so so much for your crystal clear explanation!! All the pieces literally came together as I read your explanation.

I was successfully able to create the derived classes of Survivor and then use the Factory method to set up all their parameters! :D I now have a much better understanding of how the factory method works, thanks to you!

Thanks also for your advice on the alternative method to using factories - I see now that this approach is indeed a tedious one.

Hope our paths cross again in the future! :)
My pleasure :) Enjoy programming ;)
closed account (zb0S216C)
@KRAkatau: In you example, you don't define any pure virtual functions, at all. You need = 0 at the end of the prototype in order for it to become pure virtual.

1
2
3
4
5
struct Something 
{
    virtual void FunctionA() = 0; // Pure
    virtual void FunctionB();     // Not pure
};

Wazzak
Indeed, I don't define any pure virtual functions - but that's not the point of the example. The example is there just to show that you can convert a pointer to a derived class to a pointer to a base class. And that's possible regardless of whether there are any pure virtual functions or not. But I guess even that's crystal clear for me (and you), it may become a point of confusion for a novice programmer.
Last edited on
Topic archived. No new replies allowed.