c++operator-overloadingmultiple-inheritance

The operators for my derived class do not work as intended


I made this code that has 4 classes. The SpecialCharacter class has 2 bases, Hero and Enemy, both of which have Person as their base class.

#include <iostream>

class Person {
private:
    char* name;
    int level;
public:
    Person() {
        name = nullptr;
        level = 0;
    }

    Person(char* name, int level) {
        this->name = new char[strlen(name) + 1];
        strcpy(this->name, name);
        this->level = level;
    }

    Person(const Person& p) {
        name = new char[strlen(p.name) + 1];
        strcpy(name, p.name);
        level = p.level;
    }

    virtual ~Person() {
        delete[] name;
    }

    Person& operator=(const Person& p) {
        if (this != &p) {
            delete[] name;

            name = new char[strlen(p.name) + 1];
            strcpy(name, p.name);

            level = p.level;
        }
        return *this;
    }

    bool operator<(const Person& p) const {
        return strcmp(this->name, p.name) < 0;
    }

    friend std::istream& operator>>(std::istream& is, Person& p) {
        char nameTemp[100];
        is >> nameTemp >> p.level;

        delete[] p.name;
        p.name = new char[strlen(nameTemp) + 1];
        strcpy(p.name, nameTemp);

        return is;
    }

    friend std::ostream& operator<<(std::ostream& os, const Person& p) {
        os << "name " << p.name << "\n";
        os << "level " << p.level << "\n";

        return os;
    }
};

class Hero : virtual public Person {
private:
    char* ability;
public:
    Hero() : Person() {
        ability = nullptr;
    }

    Hero(char* name, int level, char* ability) : Person(name, level) {
        this->ability = new char[strlen(ability) + 1];
        strcpy(this->ability, ability);
    }

    Hero(const Hero& h) : Person(h) {
        this->ability = new char[strlen(h.ability) + 1];
        strcpy(this->ability, h.ability);
    }

    virtual ~Hero() {
        delete[] ability;
    }

    Hero& operator=(const Hero& h) {
        if (this != &h) {
            Person::operator=(h);
            delete[] ability;
            this->ability = new char[strlen(h.ability) + 1];
            strcpy(this->ability, h.ability);
        }
        return *this;
    }

    friend std::istream& operator>>(std::istream& is, Hero& h) {
        is >> static_cast<Person&>(h);

        char tempAbil[100];
        is >> tempAbil;

        delete[] h.ability;
        h.ability = new char[strlen(tempAbil) + 1];
        strcpy(h.ability, tempAbil);

        return is;
    }

    friend std::ostream& operator<<(std::ostream& os, const Hero& h) {
        os << static_cast<const Person&>(h);

        os << "ability " << h.ability << "\n";

        return os;
    }
};

class Enemy : virtual public Person {
protected:
    char* type;
public:
    Enemy() : Person() {
        type = nullptr;
    }

    Enemy(char* name, int level, char* type) : Person(name, level) {
        this->type = new char[strlen(type) + 1];
        strcpy(this->type, type);
    }

    Enemy(const Enemy& e) : Person(e) {
        this->type = new char[strlen(e.type) + 1];
        strcpy(this->type, e.type);
    }

    Enemy& operator=(const Enemy& e) {
        if (this != &e) {
            Person::operator=(e);
            delete[] type;
            type = new char[strlen(e.type) + 1];
            strcpy(type, e.type);
        }
        return *this;
    }

    virtual ~Enemy() {
        delete[] type;
    }

    friend std::istream& operator>>(std::istream& is, Enemy& e) {
        is >> static_cast<Person&>(e);

        char temptype[100];
        is >> temptype;

        e.type = new char[strlen(temptype) + 1];
        strcpy(e.type, temptype);

        return is;
    }

    friend std::ostream& operator<<(std::ostream& os, const Enemy& e) {
        os << static_cast<const Person&>(e);

        os << "type " << e.type << "\n";

        return os;
    }
};

class SpecialCharacter : public Hero, public Enemy {
private:
    int team;
public:
    SpecialCharacter() : Person(), Hero(), Enemy() {
        team = 0;
    }

    SpecialCharacter(char* name, int level, char* ability, char* type, int team) : Person(name, level), Hero(name, level, ability), Enemy(name, level, type) {
        this->team = team;
    }

    SpecialCharacter(const SpecialCharacter& sp) : Person(sp), Hero(sp), Enemy(sp) {
        this->team = sp.team;
    }

    SpecialCharacter& operator=(const SpecialCharacter& sp) {
        if (this != &sp) {
            Hero::operator=(sp);
            this->type = sp.type;
            this->team = sp.team;
        }
        return *this;
    }

    friend std::istream& operator>>(std::istream& is, SpecialCharacter& sp) {
        is >> static_cast<Hero&>(sp);
        char temptype[100];
        is >> temptype;

        sp.type = new char[strlen(temptype) + 1];
        strcpy(sp.type, temptype);
        is >> sp.team;

        return is;
    }

    friend std::ostream& operator<<(std::ostream& os, const SpecialCharacter& sp) {
        os << static_cast<const Hero&>(sp);
        os << "type " << sp.type << "\n";

        os << "team number " << sp.team << "\n";

        return os;
    }
};

int main()
{
    Person** pers = new Person * [5];
    int i = 0, r;

    while (i < 5) {
        r = rand() % 3;

        if (r == 0) {
            std::cout << "Enter info for hero\n";
            Hero* e = new Hero();
            std::cin >> *e;
            pers[i] = e;
        }
        else if (r == 1) {
            std::cout << "Enter info for enemy\n";
            Enemy* in = new Enemy();
            std::cin >> *in;
            pers[i] = in;
        }
        else {
            std::cout << "Enter info for special character\n";
            SpecialCharacter* ps = new SpecialCharacter();
            std::cin >> *ps;
            pers[i] = ps;
        }

        i++;
    }

    for (int j = 0; j < 5; j++) {
        Hero* e = dynamic_cast<Hero*>(pers[j]);
        if (e != nullptr) {
            std::cout << *e;
            continue;
        }

        Enemy* in = dynamic_cast<Enemy*>(pers[j]);
        if (in != nullptr) {
            std::cout << *in;
            continue;
        }

        SpecialCharacter* ps = dynamic_cast<SpecialCharacter*>(pers[j]);
        if (ps != nullptr) {
            std::cout << *ps;
            continue;
        }
    }
}

I tried to overload the << and >> operators for SpecialCharacter by using static_cast, which makes it so that it first reads/prints out the objects as a Hero type, after which it reads/prints out the member values of the Enemy and the SpecialCharacter.

However, when I tested this code out in main(), it only displays the name, level and abilities for the SpecialCharacter objects, AKA the members from the Person and Hero classes.

Can anyone help me understand why this is happening? Is it because of how I used dynamic_cast in the for loop from main()? Or have I overloaded the operators for SpecialCharacter incorrectly?


Solution

  • SpecialCharacter derives from Hero. In your printing loop, your 1st dynamic_cast check for Hero* will succeed for SpecialCharacter objects, and then you continue to the next iteration, so you never get a chance to print out those objects' type and team members.

    Your printing loop should be checking for SpecialCharacter* first instead of last.

    for (int j = 0; j < 5; j++) {
    
        // DO THIS HERE!
        SpecialCharacter* ps = dynamic_cast<SpecialCharacter*>(pers[j]);
        if (ps != nullptr) {
            std::cout << *ps;
            continue;
        }
    
        Hero* e = dynamic_cast<Hero*>(pers[j]);
        if (e != nullptr) {
            std::cout << *e;
            continue;
        }
    
        Enemy* in = dynamic_cast<Enemy*>(pers[j]);
        if (in != nullptr) {
            std::cout << *in;
            continue;
        }
    
        /* NOT HERE !
        SpecialCharacter* ps = dynamic_cast<SpecialCharacter*>(pers[j]);
        if (ps != nullptr) {
            std::cout << *ps;
            continue;
        }
        */
    }