-1

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);

};
lunchbox
  • 63
  • 6
  • 1
    Where's your definition for `Adult`? – Xirema Jul 18 '18 at 19:58
  • I added the definition for Adult. I did not have a GetFirstName in it's definition. – lunchbox Jul 18 '18 at 20:01
  • 3
    Why inherit `Teacher` from `Person` and `Adult` when `Adult` is already a `Person`? – Fred Larson Jul 18 '18 at 20:02
  • @FredLarson - Good question. I did that because my constructor for a Teacher is "Teacher::Teacher(variables) : Person(firstName, lastName), Adult(other variables)". I guess based off your comment that I can omit that second inheritance and just pass everything to Adult – lunchbox Jul 18 '18 at 20:06
  • Do you want your `Adult` and `Teacher` have `Firstname` and `Lastname` and `Id`? If so, you should initialize the base class objects in your derived classes. – hiimdaosui Jul 18 '18 at 20:10
  • @hiimdaosui - Yes. And thanks for mentioning that, I did it with Teacher but not Adult – lunchbox Jul 18 '18 at 20:24
  • Are you really sure inheritance is the right way to model your requirements? How about allowing every `Person` to have any number of roles, like teacher, with any necessary ancillary data? – Deduplicator Jul 18 '18 at 20:30
  • @Deduplicator- I could go that route, sure. Really this is just a pet project of mine that was originally started in C# and now I have to learn C++ so I'm re-writing it to learn the basics of C++. – lunchbox Jul 18 '18 at 20:53

2 Answers2

1

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);`
acade
  • 245
  • 2
  • 7
0

There are multiple issues in your previous design. The direct issue that causes the compilation error is that your Teacher is inherited from both Adult and Person class. Since Adult is also a subclass of Person, both of those classes have GetLastName() method, so the compiler cannot tell which one to call.

More importantly, you should manage your hierarchy in a more correct and clear way. Semantically, an adult should also be a person and a teacher is supposed to be an adult. So why not just inherit Teacher from Adult only and make your hierarchy a linear list in your design?

Moreover, if you want complete information for your base classes, you should initialize your base class objects first in your derived class object. Use C++ initialization list to complete this.

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

public:
    Person() = default;
    Person(std::string firstName, std::string lastName) : FirstName(firstName), LastName(lastName) {}
    ~Person() = default;
    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;
}

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

};


class Teacher : 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<std::string> teacherAddress, int classroomID) 
        : Adult(firstName, lastName, emailAddress, phoneNumber, teacherAddress), ClassroomID(classroomID) {}

};



int main(void) {

    Teacher teacher("ExampleFirstName", "ExampleLastName", "example@email.com", "100-1001000", {"example address"}, 1);

    cout << teacher.GetLastName() << endl;

    return 0;
}
hiimdaosui
  • 361
  • 2
  • 12