Search code examples
c++inheritanceoperatorsoverloadingabstract

operator overloading abstract class


There is an Student abstract class, and two derived class Grad and Undergrad; and I want to overload operator in several ways.

student.h

class Student {
    protected:
    string Name;
    int Stu_num;
 
    public:
    virtual void print() = 0;
    bool operator==(const Student& x) const;

    // constructor...
}

class Grad_Student : public Student {
    private:
    string Lab;

    public:
    void print();
    bool operator==(const Grad_Student& x) const;
 
    // constructor...
}

class Undergrad_Student : public Student {
    private:
    string Major;

    public:
    void print();
    bool operator==(const Undergrad_Student& x) const;
  
    // constructor...
}

student.cpp

bool Student::operator==(const Student& x) const {
    if (this->Name == x.Name && this->Stu_num == x.Stu_num) {
        if (typeid(*this).name() != typeid(x).name()) {
            return false;
        }
        else if (!(strcmp(typeid(*this).name(), "12Grad_Student"))) {
            return *dynamic_cast<const Grad_Student *>(this) == *dynamic_cast<const Grad_Student *>(&x);
        } 
        else {
            return *dynamic_cast<const Undergrad_Student *>(this) == *dynamic_cast<const Undergrad_Student *>(&x);
        }
    } 
    else {
        return false;
    }
}

bool Grad_Student::operator==(const Grad_Student& x) const {
    return this->Lab == x.Lab;
}

bool Undergrad_Student::operator==(const Undergrad_Student& x) const {
    return this->Major== x.Major;
}

To find student object in Student *students[300] this operation == overloading works and doen't have problem, but I want to implement overloading in different way using below. How can I implement this function??

bool operator==(const Student& x, const Student& y)
{
    // do comparison...
}

Solution

  • While that may appear to work, type_info::name() is

    • implementation-dependent,
    • not guaranteed to be unique between different types,
    • not guaranteed to be the same between different executions of the same program.

    Comparing type_infos directly is reliable though, so you could do things like if (typeid(*this) == typeid(Grad_Student)) and it would work as expected.

    However, polymorphism already exists, so you don't need to implement it yourself, and you can avoid a lot of trouble (and overhead) by dispatching to a virtual function instead of enumerating subclasses.
    Something like this:

    class Student {
    public:
        bool equals(const Student& s) const
        {
            return Name == s.Name
                && Stu_num == s.Stu_num
                && typeid(*this) == typeid(s)
                && equals_internal(s);
        }
    
    private:
        virtual bool equals_internal(const Student& s) const = 0;
    
        string Name;
        int Stu_num;
    };
    
    bool operator==(const Student& lhs, const Student& rhs)
    {
        return lhs.equals(rhs);
    }
    
    class Grad_Student : public Student {
    private:
        string Lab;
    
        bool equals_internal(const Student& s) const override
        {
            return Lab == static_cast<const Grad_Student&>(s).Lab;
        }
    };
    
    class Undergrad_Student : public Student {
    private:
        string Major;
    
        bool equals_internal(const Student& s) const override
        {
            return Major == static_cast<const Undergrad_Student&>(s).Major;        
        }
    };
    

    Note that the static_casts are safe, since Student has already established the type equality.