Могу ли я указать производный класс на другую базу?(то есть: изменить семью ребенка) - PullRequest
0 голосов
/ 08 февраля 2019

Я писал код упражнения для понимания наследования классов и не мог понять, есть ли способ сделать то, что я пытался объяснить в заголовке.

Итак, что я хочу сделать, чтобыСемья и член (члены семьи) класс.Семья может иметь несколько членов, но члены могут иметь только одну семью.Но скажем, один из членов женился.Таким образом, они меняют свою семью с А на другую семью В. Есть ли способ сделать это?

#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;
}

Из этого я хотел бы получить вывод как

Family name is: Smith
Family name is: Williams

Спасибо.

(Дополнительный вопрос: есть ли способ создать переменную-член, не создавая семейную часть, но связать новую переменную-член с существующей переменной семейства при объявлении члена?)

Ответы [ 3 ]

0 голосов
/ 08 февраля 2019

Краткий ответ: Нет. Наследование устанавливается во время компиляции, вы не можете изменить его во время выполнения.

Но я не думаю, что наследование - это то, что вы ищете.Member наследует все члены и функции Family.Это не подразумевает отношения между этим Member и каким-либо конкретным экземпляром Family.Это отражено в вашем дизайне - _familyName это строка, а не ссылка на объект или что-то еще.Но вы можете иметь ссылки на другие объекты.Например, вот так:

#include <iostream>
#include <string>
#include <vector>

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

class Member {
    std::string _firstName;
    std::vector<Family*> families;
public:
    Member(Family *familyPtr) { addFamily(familyPtr) };
    void setFirstName(std::string& str) { _firstName = str;}
    void addFamily(Family *familyPtr) { families.push_back(familyPtr) };
    void printFamilies() { for (auto &ptr : families) { ptr->printFamilyName() } };
}

int main()
{
    Family Jackson("Jackson");
    Family Williams("Williams");
    Member John(&Jackson);
    Member Alice(&Williams);
    John.printFamilies();
    John.addFamily(&Williams);
    John.printFamilies();
    return 0;
}

Member не нуждается ни в каких функциях или значениях класса Family, поэтому мы не наследуем их.Вместо этого мы поддерживаем список указателей на Family объекты, к которым этот Member "принадлежит", что подразумевает связь между этим Member и этими экземплярами Family.Когда мы хотим напечатать все Family объекты, которыми владеет Member, мы просто перебираем вектор указателей и вызываем printFamilyName() для каждого из них.

0 голосов
/ 08 февраля 2019

Я не думаю, что вам нужно наследование, и то, что вы воспринимаете как наследство, не правильно.При работе с несколькими классами, которые работают вместе, будь то один класс, содержащий другой или родительские дочерние отношения, всегда нужно задать себе один вопрос: отношения между этими двумя классами: «Является ли это отношение» или это «Имеет отношение?».Когда вы задаете себе этот вопрос, и на него очень легко ответить, вы должны знать, какой тип дизайна понадобится вашим классам.

Например: собака - это млекопитающее, а у собаки есть лапы.Так что, если у нас есть 3 класса здесь.Структура будет выглядеть примерно так:

class Mammal {
    /* code */
};

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

Здесь у нас есть наследство, потому что Собака - Млекопитающее, и оно унаследует все черты, которые есть у всех Млекопитающих!

Затем мы получим это:

class Paws {
    /* code */
};

Итак, давайте вернемся к нашему "собачьему" классу

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

Надеюсь, это прояснит базовую структуру классов!


Теперь, чтобы оглянуться назад на вашу первоначальную проблему, вот что я сделал.Я сделал базовую структуру для представления FamilyMember, где все они имеют одинаковую общую информацию друг о друге.Я полностью абстрагировал фамилию, чтобы удалить все зависимости и проверить, совпадает ли фамилия, обновить или заменить ее и т. Д. Мой код выглядит следующим образом:

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

Так каквы можете видеть из небольшой программы выше;у нас нет зависимости от необходимости изменять фамилию вообще.С такой структурой, когда «Аманда» выходит замуж за «Майка».Она по-прежнему принадлежит семье «Смит», но она также присоединилась к семье «Джонс».Теперь, если вы попытаетесь получить доступ к ее индивидуальным данным через структуру, нет информации о ее фамилии.Вы можете получить ее имя, возраст и пол.Если вам нужна информация о фамилии, вам нужно извлечь ее из самого класса Family, так как она никогда не меняется!

0 голосов
/ 08 февраля 2019

Семья может иметь несколько членов, но члены могут иметь только одну семью.Но скажем, один из членов женился.Таким образом, они меняют свое семейство с A на другое семейство B. Есть ли способ сделать это?

Вам нужны отношения, определенные между объектами, а не типы объектов.Вы можете сделать это, используя контейнерные отношения между объектами, а не базовый класс - производные классовые отношения между классами.

struct Member;
struct Family
{
   std::vector<Member*> members;
}

struct Member
{
   Family* family;
}

Я дам вам понять, как определить функции-члены классовпоэтому отношения между объектами и временем жизни объектов поддерживаются надежным образом.

...