我可以将派生的 class 指向不同的基础吗? (即:更改 child 的家庭)

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

我正在编写一些练习代码来理解 class 继承,但我无法弄清楚是否有办法实现我在标题中试图解释的内容。

所以我想做的就是拥有Family和Member(家庭成员)class。一个家庭可以有多个成员,但成员只能有一个家庭。但是假设其中一位成员结婚了。所以他们正在将他们的家庭从 A 改为其他家庭 B。有没有办法做到这一点?

#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

谢谢。

(额外的问题是,有没有办法在不构造family部分的情况下创建成员变量,而是在声明成员的同时将新成员变量绑定到现有的family变量?)

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?

您需要定义对象之间的关系,而不是对象类型。您可以通过使用对象之间的容器包含关系来做到这一点,而不是 class - classes.

之间的派生 class 关系。
struct Member;
struct Family
{
   std::vector<Member*> members;
}

struct Member
{
   Family* family;
}

我将让您了解如何定义 classes 的成员函数,以便以稳健的方式维护对象之间的关系和对象的生命周期。

简短回答:不。继承是在编译时设置的,您不能在运行时更改它。

但我不认为继承是您要找的东西。 Member继承了Family的所有成员和函数。它并不意味着 MemberFamily 的任何特定实例之间存在关系。这反映在您的设计中 - _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不需要classFamily的任何函数或值,所以我们不继承它们。相反,我们维护一个指向 Family 对象的指针列表,这个 Member "belongs" 指向,因此暗示了这个 MemberFamily 的那些实例之间的关系。当我们想要打印 Member 拥有的所有 Family 对象时,我们只需遍历指针向量并在每个指针上调用 printFamilyName()

我认为你不需要继承,你认为继承是不正确的。当处理多个一起工作的 classes 时,无论是一个 class 包含另一个关系还是父子关系,总是有一个问题要问你自己:两个 classes 之间的关系是它是 "Is a relationship" 还是 "Has a relationship"。当您问自己这个问题并且很容易回答时,您应该知道您的 classes 需要什么设计类型。

例如:狗是哺乳动物,狗有爪子。所以如果我们这里有 3 classes。结构看起来像这样:

class Mammal {
    /* code */
};

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

这里我们有遗传,因为狗是哺乳动物,会继承所有哺乳动物的所有特征!

接下来我们会有这个:

class Paws {
    /* code */
};

那么让我们回到我们的 "dog" class

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

我希望这可以解决 classes 的基本结构问题!


现在回顾一下您最初的问题,这是我所做的。我制作了一个基本结构来表示 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;
}

所以从上面的小程序可以看出;我们根本不需要修改姓氏。这样的结构,当"Amanda"嫁给"Mike"。她仍然属于"Smith"家族,但她也加入了"Jones"家族。现在,如果您尝试通过该结构访问她的个人数据,则没有关于她姓氏的信息。您可以检索她的名字、年龄和性别。如果您想要姓氏的信息,您必须从家庭 class 本身检索它,因为它永远不会改变!