0
votes

C ++ Interaction entre deux classes dans une fonction

J'essaie de faire une tâche relativement simple ici et je ne suis pas sûr de savoir comment y aller.

J'ai deux classes d'intérêt parent code> et enfant code>. Les deux sont un cas particulier de la classe humaine. Je les crée en tant que telle. P>

Bit pertinent de main.cpp strong>: p> xxx pré>

la parent.h L'en-tête comprend une fonction appelée addchild () code>. Ce qu'il fait est simplement ajoute un enfant à un vecteur d'enfants à l'intérieur d'un objet parent. P>

Bit pertinent de parent.h strong>: p> xxx pré>

Ce que je voudrais réaliser est pour le addchild ( ) code> fonction pour ajouter simultanément un parent à l'enfant aussi. C'est-à-dire que faire quelque chose comme: p> xxx pré>

ci-dessus, moi-même désigne le peu que je ne sais pas comment coder. P>

Alors quand je cours Ceci: P>

In member function 'void Parent::addChild(Child&)':
invalid use of incomplete type 'class Child'
         child.parents.emplace_back(*this);
error: forward declaration of 'class Child'
 class Child;


6 commentaires

Y a-t-il un humain qui n'est pas un enfant? Qu'est-ce que est (fonctionnalité) A parent quel humain (ou enfant ) ne fait pas? En bref: votre conception n'est pas très utile.


C'est un exemple de jouet pour illustrer ce que je veux la fonction addChild () à faire - je ne suis pas inquiet pour la conception à ce stade.


Moi-même est ceci resp. * ceci


Pourquoi ne pas simplement utiliser ceci ?


Dans les membres non statiques de toute classe, le pointeur (fourni par le compilateur) identifie l'objet actuel. Au-delà de cela, les enfants et les parents ne sont pas des types distincts d'humains (assez de personnes sont simultanément). Je n'utiliserais donc pas humain comme classe de base. Au lieu de cela, faites sans parent et enfant comme des classes distinctes. Puis chaque humain peut avoir un ensemble d'enfants et un ensemble de parents, c'est-à-dire d'être un parent ou un enfant (ou avoir des parents et des enfants) est un attribut de chaque humain , Pas la base de la définition de différents types de humain .


Voir ma réponse de réponse sur votre question ajoutée.


4 Réponses :


0
votes

Vous avez un problème lorsque vous utilisez Void AddChild (Human Ahuman) sans & vous devez faire du vide AddChild (Human & Ahuman) Si vous avez changé pour enregistrer dans l'objet sans et vous copiez 2 fois les objets 1 dans l'appel fonctionner et un lorsque vous insérez à AddChild (Child1); Moi-même peut être ceci mais vous devez changer le vecteur pour ne pas obtenir d'objets


0 commentaires

3
votes

Je crains que vous ayez un problème xy et de mélanger d'importants concepts de polymorphisme d'objet et de conception C ++ en général, mais voici une solution à ce que vous avez posé:

#include <vector>
#include <memory>

struct Human {
    virtual ~Human() = default;
};

struct Parent;

struct Child: Human{
    Child(std::string) {}
    void addParent(std::weak_ptr<Parent> aParent) {
        Parent = aParent;
    }
private:
    std::weak_ptr<Parent> Parent;
};

struct Parent: Human, std::enable_shared_from_this<Parent> {
    Parent(std::string) {}
    void addChild(Child aChild){
        aChild.addParent(shared_from_this());
        Children.push_back(aChild);

    }
private:
    std::vector<Child> Children;
};



int main() {
    auto parent1 = std::make_shared<Parent>("Albert"); //create an object of class Parent parent1 with a name Albert.
    Child child1("John");//create an object of a class Child child1 named John.
    parent1->addChild(child1);
}


4 commentaires

L'ajout faim_ptr / partagé_ptr au code de quelqu'un qui apprend est surchargé?


Oui, mais puisqu'il semble têtu de la conception de classe donnée, cela doit être fait. Sinon, vous obtiendrez des effets encore plus surprenants comme, de la tranchée et des problèmes de vie, c'est-à-dire des défauts SEG. De cette façon, j'ai déjà recommandé au PO de reconsidérer son design initial. Et apprendre davantage sur la durée de vie, les classes de stockage et le POO en général. Bien sûr, on pouvait simplement refuser de répondre aux questions de Newbie car ils sont faux, mais ceux-ci ne le font pas, au moins on devrait montrer de bonnes pratiques dans la mesure du possible. Et les pointeurs bruts sont dangereux et pas les meilleurs pratices.


S'il vous plaît jeter un oeil à mon commentaire, et mon implémentation . Il semble que vous ayez une idée fausse sur la façon dont std :: vecteur fonctionne.


Merci pour une explication détaillée. C'est très utile!



2
votes

Vous avez principalement 2 numéros:

  • Vous passez par valeur au lieu de référence, vous ne modifiez donc qu'une copie
  • Vous avez la tranchée d'objet: std :: vecteur stocker uniquement une partie humaine de parent / enfant . .

0 commentaires

0
votes

Vous avez rencontré un problème courant des programmeurs de Novice OOP: vous essayez de résoudre un problème relationnel en prolongeant des classes de l'OPO, au lieu de créer une classe relationnelle.

L'approche novice forte> p> Tout d'abord, continuons avec votre approche pour un peu ... bien sûr, chaque parent code> a un enfant code> et chaque enfant code> a un Parent code> et la manière naturelle semble stocker ces relations dans chaque classe. Ainsi: P>

//Given, that we only have basic functionality, a struct is sufficient here...
struct ParentalRelation
{
    Child child;
    Parent parent;
};


14 commentaires

Bonjour, merci beaucoup pour une explication aussi détaillée - très appréciée pour un débutant. Je pense que je rencontre toujours un problème de déclaration avancé - pouvez-vous aider? J'ai ajouté le code et les erreurs qu'il cède dans la modification de la question.


Votre code ne compilera ni ne fonctionnera, car un conteneur doit connaître la taille de ses éléments. (Dans ce cas std :: vecteur )


@Kivis pas de problème! Désolé, c'est un peu délicat et j'ai laissé de côté quelques détails de la mise en œuvre pour rendre le code plus clair ... Ici, vous ne pouvez pas définir les fonctions membres à l'intérieur de la classe. Vous devez les déclarer et ensuite faire la définition à l'extérieur. Voici une implémentation de travail: goodbolt.org/z/hd4xhp


@Superlokkus Malgré votre prédiction, il compile et ça marche: D aussi loin que je le comprends (cela pourrait être faux), std :: vecteur est juste un pointeur sur un emplacement de mémoire et Parce que les pointeurs ont une taille indépendante de type, le compilateur a déjà toutes les informations nécessaires à compiler parent .


Mon idée fausse est qu'ils ont changé l'exigence de type de T dans le vecteur , du type complet de C ++ 11 à C ++ 14 aux exigences de complétude allocator en C ++ 17.


Mais merci de savoir que si vous ne m'avez pas dit, je n'aurais pas remarqué que le changement de C ++ 17.


@Superlokks Je suis désolé, mais je ne comprends pas ce que vous dites.


Votre code est toujours faux pour les C + 11 et 14 et ne garantit pas la compilation des bibliothèques standard pré-c ++ 17. C'est aussi la raison pour laquelle il n'a pas compilé sur le compilateur en ligne donné par l'OP.


@Superlokkus b b mais compile ... aa et travaille ... (voir goodbolt.org/z/hd4xhp < / a>) Il vous suffit d'obtenir l'ordre des déclarations et des définitions ....


@Superlokkus compare votre code avec le mien: vous définissez un parent célibataire pour l'enfant. Vous avez raison, cela ne fonctionne pas ... Cependant, ce n'est pas ce que je fais. J'ai un vecteur qui fonctionne juste bien.


@Superlokkus Je pense, je vous comprends du problème maintenant. Je l'ai posté comme une question séparée à: Stackoverflow.com/q/56975491/4759339


Tout fonctionne pour moi. Merci Jan! Et je suis content que cela a commencé une discussion :)


@ Jan.Sende Je me demandais, pourquoi ajoutez-vous également l'opérateur d'adresses et après les fonctions AddChild, AddParent et LinkchildToparent? J'essaie de comprendre cette adresse de mémoire et de l'entreprise des pointeurs en tout. Merci!


@Kivis Le & peut avoir plusieurs significations. À ce stade, il marque les paramètres comme un Référence . Ils se comportent un peu comme des pointeurs, mais ne sont pas exactement les mêmes. Vous en avez besoin parce que parent parent éditerait une copie de l'objet et laissez l'original derrière. Cependant, on pourrait écrire une version parent * parent à la place.