Search code examples
c++ooppolymorphismdiamond-problem

C++ printing with Diamond of death


first let me explain my hierarchy :

        Person
       /     \
   Student Employee
       \     /
       Intern

Each class has an output function of their own , which prints their data members, and I have to print Person only once. The problem is that Student and Employee are not abstract classes, and people will also make an object of their type, so I can't only call the output function on the Intern level.

As you will see in the following code, I've managed to solve this, but I think this is ugly and not very polymorphic . I've created an additional output function so it will work for all cases. Is there a better way of achieving this ?

class Person {
    string name;
    int id;
public:
        virtual void output(ostream& out) {
        out << name << "," << id;
    }
}

Student:

class Student : virtual public Person {
    string major;
    int year;
public:
    virtual void output(ostream& out) {
        Person::output(out);
        out << "," << major << "," << year;
    }
    virtual void outputStudOnly(ostream& out) {
        out << "," << major << "," << year;
    }
};

Employee:

class Employee : virtual public Person{
    string jobTitle;
public:
    virtual void output(ostream& out) {
        Person::output(out);
        out << "," << jobTitle;
    }
    virtual void outputEmpOnly(ostream& out) {
        out << "," << jobTitle;
    }
};

And Intern :

class Intern : public Student, public Employee {
public:
    virtual void output(ostream& out) {
        Person::output(out);
        Student::outputStudOnly(out);
        Employee::outputEmpOnly(out);
    }
};

Solution

  • That what template method is for. Here is how I would write this code:

    class Person {
        string name;
        int id;
    public:
            void output(ostream& out) {
            out << name << "," << id;
            output_impl(out);
        }
    private:
           virtual void output_impl(ostream& ) {}
    };
    
    class Student : virtual public Person {
        string major;
        int year;
    private:
        virtual void output_impl(ostream& out) {
            out << "," << major << "," << year;
        }
    
    };
    
    class Employee : virtual public Person {
        string jobTitle;
    private:
        virtual void output_impl(ostream& out) {
            out << "," << jobTitle;
        }
    };
    
    class Intern : public Student, public Employee {
    private:
        virtual void output_impl(ostream& out) {
            Student::output_impl(out);
            Employee::output_impl(out);
        }
    };
    

    And than you call output on the object.