I have an assignment due Friday to make a family tree. Started to code in January. My reviews from the teacher for this code was that the use of pointers was horrendous and it wasn't OOP enough. This code compiles and works. What can I do better to make the code more object oriented?
The best commentary was "It's horrendous to see pointers in the wild like this". At the same time, he taught us, so my assignment partner and I don't know what else to do. It seems like every time we ask for help, the code gets more complicated than necessary and we go further away from C++. I know that I have to create a node that takes in a person, but is there anything else?
This code is made to let a user put in him/herself and to add parents, grandparents etc. You can edit, delete and search.
class person
{
private:
public:
std::string firstName; // variable to hold the firstname of the person
std::string lastName; // variable to hold the lastname of the person
int yearOfBirth; // variable to hold the year of birth
int age; // variable to hold the age of person
int alive; // variable to hold data
int sex; // variable to hold the gender of the person
person *left;
person *right;
person();
~person();
void getData();
};
person::person() // constructor outside the class
{
left = right = nullptr;
firstName = "";
lastName = "";
yearOfBirth = 0;
age = 0;
alive = 0;
sex = 0;
}
person::~person() = default; //destructor of person::person (check if this code runs and are okey!!)
void ignoreLine()
{
std::cin.clear();
std::cin.ignore(INT_MAX, '\n');
}
void person::getData() // get information about a person
{
char gender;
std::cout << "\nFirstname of the person: " << std::endl;
std::cin >> firstName;
std::cout << "Lastname of the person: " << std::endl;
std::cin >> lastName;
std::cout << "Age of " << firstName << ": " << std::endl;
while (!(std::cin >> age) or (age < 0) or std::cin.fail()) // check if the inputs only contains positives int.
{
std::cin >> age;
std::cout << "Only positives number allowed: " << std::endl;
ignoreLine();
}
std::cout << "What is the sex of " << firstName << " (m/f): " << std::endl;
std::cin >> gender;
switch (gender) // all other int, char etc, than m/M is considered as female. Maybe change later, but good for now.
{
case 'm':
case 'M':
sex = 1;
break;
}
ignoreLine(); // "pause" the program until the user press "Enter"
}
class familyTree
{
private:
public:
person *root;
person *search(const std::string&);
person *traverseLeft(person *, const std::string&);
person *traverseRight(person *, const std::string&);
familyTree();
void addNewPerson();
void addMother(person *, person *);
void addFather(person *, person *);
static void show(person *);
void printInOrder(person *, int);
};
familyTree::familyTree()
{
root = nullptr;
}
void familyTree::addMother(person *a, person *b) // to add b as the mother of a
{
if (a->left == nullptr)
{
a->left = b;
}
else
{
addMother(a->left, b);
}
}
void familyTree::addFather(person *a, person *b)// to add b as the father of a
{
while (a->right != nullptr)
a = a->right;
a->right = b;
}
person *familyTree::traverseLeft(person *ptr, const std::string& person)
{
ptr = ptr->left;
while (ptr != nullptr)
{
if ((ptr->firstName) == person) {
return ptr;
}
else if (traverseRight(ptr, person) != nullptr)
{
return traverseRight(ptr, person);
}
else
{
ptr = ptr->left;
}
}
return nullptr;
}
person *familyTree::traverseRight(person *ptr, const std::string& person)
{
ptr = ptr->right;
while (ptr != nullptr)
{
if ((ptr->firstName) == person)
{
return ptr;
}
else if (traverseLeft(ptr, person) != nullptr)
{
return traverseLeft(ptr, person);
}
else
ptr = ptr->right;
}
return nullptr;
}
void familyTree::addNewPerson()
{
auto *temp = new struct person;
temp->getData();
std::string personChild;
if (root == nullptr)
{
std::cout << "\nFirst person added to the family!" << std::endl;
root = temp;
}
else // if there exists a person in the tree, add the new person as a relative to a previous
{
std::cout << "Enter the name of the person " << temp->firstName << " is the parent to: " << std::endl;
std::cin >> personChild;
if (familyTree::search(personChild)) //tests if the person entered is found int the tree, if yes it continues.
{
int opt;
std::cout << "\nWhat is the family relation? " << std::endl;
std::cout << "(1) if " << temp->firstName << " is the Mother to " << personChild << std::endl;
std::cout << "(2) if " << temp->firstName << " is the Father to " << personChild << std::endl;
std::cout << "Enter: " << std::endl;
std::cin >> opt;
ignoreLine(); // "pause" the program until the user press "Enter"
while (std::cin.fail() or opt < 1 or opt > 2)
{
std::cout << "\nOnly a number of 1 or 2 is accepted!" << std::endl;
std::cout << "Enter: " << std::endl;
std::cin >> opt;
ignoreLine(); // "pause" the program until the user press "Enter"
}
switch (opt)
{
case 1:
addMother(search(personChild), temp);
std::cout << temp->firstName << " is now added as the mother!" << std::endl;
break;
case 2:
addFather(search(personChild), temp);
std::cout << temp->firstName << " is now added as the father!" << std::endl;
break;
}
}
// else
// {
// maybe make a code that loops the "enter name" until it's correct? Or just go straight back to main menu?
// }
}
}
void familyTree::printInOrder (person *person, int space) //print its persons using in order traversal
{
auto count = 7; //using count for how much space between generations (horizontal)
space += count;
if (person != nullptr)
{
if(person->left != nullptr)
{
printInOrder(person->left, space);
}
std::cout << std::endl;
for (int i = count; i < space; i++)
std::cout << " ";
std::cout << person->firstName << "\n";
if(person->right != nullptr)
{
printInOrder(person->right, space);
}
}
else
{
std::cout << "No tree exist!" << std::endl;
ignoreLine(); // "pause" the program until the user press "Enter"
return;
}
}
person *familyTree::search(const std::string& per) // to search for a person
{
person *ptr = root;
if ((ptr->firstName) == per)
{
return ptr;
}
else if (traverseRight(root, per) != nullptr)
{
return traverseRight(root, per);
}
else if (traverseLeft(root, per) != nullptr)
{
return traverseLeft(root, per);
}
else
{
std::cout << "\nNo person found with the given name" << std::endl;
ignoreLine(); // "pause" the program until the user press "Enter"
return nullptr;
}
}
void familyTree::show(person *ptr) // to show the information of a particular person
{
std::string sex = "Female";
if (ptr->sex)
{
sex = "Male";
}
std::cout << "\nName: " << ptr->firstName << " " << ptr->lastName << std::endl;
std::cout << "Age: " << ptr->age << std::endl;
std::cout << "Sex: " << sex << std::endl;
std::cin.ignore();
}
void showMainMenu() // hold the output for the main menu
{
std::cout << "Welcome" << std::endl;
std::cout << "Please enter a number for your choice below:\n" << std::endl;
std::cout << "(1) Add new person to tree" << std::endl;
std::cout << "(2) Show information for a person" << std::endl;
std::cout << "(3) Print complete family-tree" << std::endl;
std::cout << "(4) Used for testing new choices" << std::endl;
std::cout << "(0) Quit" << std::endl;
std::cout << "\nYour choice: " << std::endl;
}
int main()
{
familyTree fT; // used to access/init. familytree class.
int option, exit = 0;
std::string temp, str;
while (exit == 0)
{
showMainMenu();
std::cin >> option;
while (std::cin.fail())
{
ignoreLine();
std::cout << "\nOnly a number between 0 and 10 is allowed: ";
std::cin >> option;
}
switch (option)
{
case 1:
fT.addNewPerson();
break;
case 2:
std::cout << "Enter name of person to show information: ";
std::cin >> temp;
fT.show(fT.search(temp));
break;
case 3:
fT.printInOrder(fT.root, 0);
break;
case 4:
/* n/a */
break;
case 0:
exit = 1;
break;
}
std::cout << "\nPress enter to continue.." << std::endl;
ignoreLine();
}
return 0;
}