Search code examples
c++derived-class

Can I point a derived class to a different base? (i.e: change the family of a child)


I was writing some exercise code to understand class inheritance and I couldn't figure out If there is a way to do what I tried to explain in the title.

So what I want to do to have Family and Member (family members) class. A family can have multiple members but members can have only one family. But let's say one of the members got married. So they are changing their family from A to other family B. Is there a way to do that?

#include <iostream>
#include <string>

class Family {
    std::string _familyName;
public:
    Family();
    void setFamilyName(std::string& str) { _familyName = str;}
    void printFamilyName() {
        std::cout << "Family name is: " << _familyName << std::endl;
    }
}

class Member : public Family {
    std::string _firstName;
public:
    Member();
    void setFirstName(std::string& str) { _firstName = str;}
    void changeFamily(Family *f) {} // What do i do here ?

}

int main(){
    Member m;
    m.setFamilyName("Smith");
    m.setFirstName("John");
    m.printFamilyName();
    Family f;
    B.setFamilyName("Williams");
    m.changeFamily(&f);
    m.printFamilyName();
    return 0;
}

From this, I would like to get an output as

Family name is: Smith
Family name is: Williams

Thank you.

(An extra question is, is there a way to create a member variable without constructing the family part, but to bind the new member varible to an existing family variable while declaring the member ?)


Solution

  • I don't think you need inheritance, and what you perceive to be inheritance is not correct. When working with multiple classes that work together either it be one class containing another or parent child relationship, there is always one question to ask yourself: The relationship between the two classes is it a "Is a relationship" or is it "Has a relationship". When you ask yourself that question and it is very easy to answer then you should know what design type your classes will need.

    For example: A dog is a mammal and A dog has paws. So if we have 3 classes here. The structure would look something like this:

    class Mammal {
        /* code */
    };
    
    class Dog : public Mammal {
        /* code */
    };
    

    Here we have inheritance because a Dog IS A Mammal and will inherit all of the traits that all Mammals have!

    Next we would have this:

    class Paws {
        /* code */
    };
    

    So let's go back to our "dog" class

    class Dog : public Mammal {
    private:
        Paws paws; // this is a member of Dog because a Dog HAS PAWS!
    };
    

    I hope this clears things up with the basic structure of classes!


    Now to look back at your initial problem, here is what I have done. I made a basic struct to represent a FamilyMember where they all have the same information about each other in common. I abstracted out the last name completely to remove any dependencies and having to check if the last name is the same and to update or replace it etc. My code looks like this:

    struct FamilyMember {
        std::string firstName_;
        unsigned int age_;
        char gender_;
    
        FamilyMember() = default;
        FamilyMember(const std::string& firstName, unsigned int age, char gender) :
            firstName_(firstName),
            age_(age),
            gender_(gender)
        {}
    };
    
    class Family {
    private:
        std::string familyName_;
        std::vector<FamilyMember> members_;
    
    public:
        Family() = default;
        explicit Family(const std::string& familyName) : familyName_( familyName ) {
        }
    
        void addMember(FamilyMember& member) {
            members_.push_back(member); 
        }
    
        FamilyMember& getMember(unsigned int idx) {
            return members_.at(idx);
        }
    
        std::vector<FamilyMember>& getFamily() {
            return members_;
        }
    
        const std::string& getFamilyName() const { return familyName_; }
    };
    
    int main() {
        Family Smith("Smith");
        FamilyMember John("John", 32, 'M');
        FamilyMember Sarah("Sarah", 29, 'F');
        FamilyMember Amanda("Amanda", 19, 'F');
        Smith.addMember(John);
        Smith.addMember(Sarah);
        Smith.addMember(Amanda);
    
        std::cout << "Meet the " << Smith.getFamilyName() << "s:\n";
        for (auto& m : Smith.getFamily()) {
            std::cout << m.firstName_ << " " << Smith.getFamilyName() << " " << m.age_ << " " << m.gender_ << '\n';
        }
    
        Family Jones("Jones");
        FamilyMember Tom("Tom", 44, 'M');
        FamilyMember Mary("Mary", 43, 'F');
        FamilyMember Mike("Mike", 21, 'M');
        Jones.addMember(Tom);
        Jones.addMember(Mary);
        Jones.addMember(Mike);
    
        std::cout << "Meet the " << Jones.getFamilyName() << "s:\n";
        for (auto& m : Jones.getFamily() ) {
            std::cout << m.firstName_ << " " << Jones.getFamilyName() << " " << m.age_ << " " << m.gender_ << '\n';
        }
    
        std::cout << "We present to you today the Union between: "
            << Jones.getMember(2).firstName_ << " " << Jones.getFamilyName() << " and "
            << Smith.getMember(2).firstName_ << " " << Smith.getFamilyName() << '\n';
    
        Jones.addMember(Amanda);
        std::cout << "We now have Mr. " << Jones.getMember(2).firstName_ << " " << Jones.getFamilyName() << " and "
            << "Mrs. " << Jones.getMember(3).firstName_ << " " << Smith.getFamilyName() << " " << Jones.getFamilyName() << '\n';    
    
        return 0;
    }
    

    So as you can see from the small program above; we do not have the dependency of having to modify the last name at all. With this kind of structure, when "Amanda" marries "Mike". She still belongs to the "Smith" family, but she has also joined with the "Jones" family. Now if you try to access her individual data through the structure, there is no information about her last name. You can retrieve her first name, age and gender. If you want the information for the last name, you have to retrieve that from the Family class itself as it never changes!