Search code examples
c++inheritancemultiple-inheritance

c++ inheritance/multi-inheritance ambiguous call


Beginner C++ question:

I have a class Person that has protected variables FirstName and LastName:

class Person
{
protected:
    int Id;
    std::string FirstName;
    std::string LastName;

public:
    Person();
    Person(std::string firstName, std::string lastName);
    ~Person();
    std::string GetPersonInfo() const;
    std::string GetFirstName() const;
    std::string GetLastName() const;
};

inline std::string Person::GetPersonInfo() const {
    return FirstName + " " + LastName;
}

inline std::string Person::GetFirstName() const {
    return FirstName;
}

inline std::string Person::GetLastName() const {
    return LastName;
}

I have a Teacher class that inherits from Person (and an Adult Class)

class Teacher :
    public Person, public Adult
{
private:
    int ClassroomID;
public:
    Teacher() = default;
    ~Teacher() = default;
    Teacher(std::string firstName, std::string lastName, std::string emailAddress, std::string phoneNumber,
        std::vector<Address> teacherAddress, int classroomID);

};

In my main() I have the following:

vector<Teacher> teachers = TeacherRepository.RetrieveTeachers();
            for (Teacher teacher : teachers) {
                cout << teacher.GetFirstName(); }

When I start to type "teacher." I see "GetFirstName" appear as an option, however; it is throws a compiler error that "Teacher::GetFirstName is ambiguous"

What have I done wrong?

EDIT: Definition for Adult

class Adult :
    public Person
{
protected:
    std::string Email;
    std::string PhoneNumber;
    std::vector<Address> address;
public:
    Adult() = default;
    ~Adult() = default;
    Adult(std::string emailAddress, std::string phoneNumber, std::vector<Address> address);
    Adult(std::string emailAddress, std::string phoneNumber);

};

Solution

  • You have incorrect hierarchy. Teacher inherit from Person and Adult at the same time and Adult inherit Person too. What do you want compiler call when you write Teacher::GetFirstName? Maybe Person::GetFirstName or Adult::Person::GetFirstName. Moreover you will have two exemplars of Person's variables.

    Decisions:

    1. virtual inheritance:

      class Adult : virtual public Person {...}; class Teacher : virtual public Person, public Adult {...};

    more here

    1. teacher's basic class must be Adult only:

      class Teacher : public Adult {...};

    As bad option: you can to indicate explicit which certainly method you want to call:

    `Teacher t = ...;
    t.Adult::GetFirstName();`
    

    Bonus: Don't pass arguments by value, in your case will be better pass arguments as constant reference.

    `Person(const std::string& firstName, const std::string& lastName);`
    

    Instead

     `Person(std::string firstName, std::string lastName);`