I have an exercise to practice multiple inheritance and polymorphism and something is not going well. The exercise includes 4 classes I need to build:
- Creature
- char * name
- int age
- int numOfOffsprings
- Vampire : Creature
- int lightSensitivity
- Vampire** offsprings
- Werewolf : Creature
- int humanHours
- int werewolfHours
- Werewolf** offsprings
- VampireWerewolf : Vampire, Werewolf
- Creature** offsprings
There is a method called printInfo that prints out the info about each class. As you might expect, the use of the function is overridden in every class while also printing the info of the parents. When I try to use printInfo from VampireWerewolf I get the Creature part twice and I'm not sure what should I do to make it run once. Attaching the code below
Creature.h
#ifndef CREATURE_H
#define CREATURE_H
#include <iostream>
using namespace std;
class Creature {
protected:
char* m_name;
int m_age;
int m_numOfOffsprings;
public:
// Constructors
Creature(): m_name(nullptr), m_age(0), m_numOfOffsprings(0) {}
Creature(const char* name, int age, int numOfOffsprings):
m_age(age),
m_numOfOffsprings(numOfOffsprings) {
m_name = new char[strlen(name) + 1];
strcpy_s(m_name, strlen(name) + 1, name);
}
char* getName() { return m_name; }
int getAge() { return m_age; }
int getNumOfOffsprings() { return m_numOfOffsprings; }
virtual void printInfo() {
cout << "===Creature printInfo===" << endl << endl;
cout << "Name: " << m_name << endl;
cout << "Age: " << m_age << endl;
cout << "Number of offsprings: " << m_numOfOffsprings << endl;
}
};
#endif // !CREATURE_H
Vampire.h
#ifndef VAMPIRE_H
#define VAMPIRE_H
#include <iostream>
#include <array>
#include "Creature.h"
using namespace std;
class Vampire : public virtual Creature {
int m_lightSensitivity;
Vampire** m_offsprings;
public:
// Constructors
Vampire(): m_lightSensitivity(0), m_offsprings(nullptr) {}
Vampire(char* name, int age, int numOfOffsprings, int lightSensitivity, Vampire** offsprings):
Creature(name, age, numOfOffsprings), m_lightSensitivity(lightSensitivity) {
if (numOfOffsprings <= 0) { m_offsprings = nullptr; }
else {
m_offsprings = new Vampire * [numOfOffsprings];
for (int i = 0; i < numOfOffsprings; i++) {
m_offsprings[i] = offsprings[i];
}
}
}
virtual void printInfo() override {
Creature::printInfo();
cout << "===Vampire printInfo===" << endl << endl;
cout << "Light sensitivity: " << m_lightSensitivity << endl;
for (int i = 0; i < m_numOfOffsprings; i++) {
cout << "- Offspring " << i + 1 << ": " << m_offsprings[i]->m_name << endl;
}
}
};
#endif // !VAMPIRE_H
Werewolf.h
#ifndef WEREWOLF_H
#define WEREWOLF_H
#include <iostream>
#include "Creature.h"
using namespace std;
class Werewolf: public virtual Creature {
int m_werewolfHours, m_humanHours;
Werewolf** m_offsprings;
public:
// Constructors
Werewolf() : m_werewolfHours(0), m_humanHours(0), m_offsprings(nullptr) {}
Werewolf(char* name, int age, int numOfOffsprings, int werewolfH, int humanH, Werewolf** offsprings):
Creature(name, age, numOfOffsprings),
m_werewolfHours(werewolfH),
m_humanHours(humanH) {
if (numOfOffsprings <= 0) { m_offsprings = nullptr; }
else {
m_offsprings = new Werewolf * [numOfOffsprings];
for (int i = 0; i < numOfOffsprings; i++) {
m_offsprings[i] = offsprings[i];
}
}
}
virtual void printInfo() override {
Creature::printInfo();
cout << "===Werewolf printInfo===" << endl << endl;
cout << "Werewolf hours: " << m_werewolfHours << endl;
cout << "Human hours: " << m_humanHours << endl;
for (int i = 0; i < m_numOfOffsprings; i++) {
cout << "- Offspring " << i + 1 << ": " << m_offsprings[i]->m_name << endl;
}
}
};
#endif // !WEREWOLF_H
VampireWerewolf.h
#ifndef VAMPIRE_WEREWOLF_H
#define VAMPIRE_WEREWOLF_H
#include <iostream>
#include "Vampire.h"
#include "Werewolf.h"
using namespace std;
class VampireWerewolf : public Vampire, public Werewolf {
Creature** m_offsprings;
public:
VampireWerewolf(
char* name,
int age,
int numOfOffsprings,
int lightSensitivity,
int werewolfHours,
int humanHours,
Creature** offsprings):
Creature(name, age, numOfOffsprings),
Vampire(name, age, numOfOffsprings, lightSensitivity, nullptr),
Werewolf(name, age, numOfOffsprings, werewolfHours, humanHours, nullptr) {
if (numOfOffsprings <= 0) { m_offsprings = nullptr; }
else {
m_offsprings = new Creature * [numOfOffsprings];
for (int i = 0; i < numOfOffsprings; i++) {
m_offsprings[i] = offsprings[i];
}
}
}
virtual void printInfo() {
Vampire::printInfo();
Werewolf::printInfo();
// <Additional VampireWerewolf info below>
}
};
#endif // !VAMPIRE_WEREWOLF_H
Main.cpp
#include <iostream>
#include "Creature.h"
#include "Vampire.h"
#include "Werewolf.h"
#include "VampireWerewolf.h"
using namespace std;
int main() {
VampireWerewolf ackbar((char*)"Ackbar", 100, 0, 50, 24, 0, nullptr);
ackbar.printInfo();
return 1;
}
I used virtual signature for the class and the method and also added the override keyword to Vampire::printInfo() and Werewolf::printInfo().
std::endldoes. Use'\n'to end a line unless you have a good reason not to.ackbar((char*)"Ackbar"-- don't do that. The problem is that the constructor for VampireWerewolf` takeschar*when it should take aconst char*. A cast is hardly ever the right answer to a problem like this.Creaturea virtual base ofWerewolfandVampire. Unfortunately, that makes some things complicated. The constructors ofVampireWerewolf,Werewolf, andVampirehandle the problem correctly for construction:Creatureonly gets constructed once. Similarly, its destructor will only run once. But you're on your own for any other member functions; you have to have some logic to recognize that the base class has already been printed so that it doesn't get printed again.using namespace std;is not a good idea in source files. Doing it in a header file is much worse.std::stringfor names and texts; pointers to characters are messy.