Patrick Dezecache
Patrick Dezecache

Reputation: 217

C++ : class A reference classe B (in a vector) and class B reference A (only one)

LAST EDIT: FINAL CODE LIES AT TH END OF THE MESSAGE

i am coming from Java and I am looping for a while :

I try to implement navigability from classes Zoo to Animal and Animal to Zoo.

Q.1) did I write it the right way ? (source code on bottom)

I have got an compile error related to "stl_vector.h" class Zoo : animals.push_back(a); with message : "error:cannot increment a pointeur to incomplete type Animal"

Q.2 ) is it related to the way I implemented navigability ?

In the main.cpp, i will add animals to the zoo :

Zoo z();
std::string nom("sheeta");
Animal a(z,nom);

Q.3) the Animal constructor exists ... : why does the compiler tell me that

compile error : "no matching function for call Animal::Animal(Zoo (&)(), std::string &)

Q.4) what is the c++ way to write :

z.addAnimal(Animal(z,nom));

EDIT1 : here is what i want to implement : a zoo contains n animals, an animal knows which zoo it belongs to

LAST EDIT : picture updated with your help ==========================================

enter image description here

many thanks for helping !


Here are the changes i made from your precious comments :

LAST EDIT IN SOURCE CODE - 2015-12-18 07:20 gmt ===============================================

file Zoo.h

#ifndef ZOO_H
#define ZOO_H

#include <vector>

** ADDED : include Animal.h **

#include "Animal.h"

class Zoo
{
  private:
    std::string zooName; // no importance : name of the zoo
    std::vector<Animal> animals;  // list of animals
  public:
    Zoo(std::string  n); // no importance : name of the zoo

** ADDED : const & **

    void addAnimal(Animal const & a); 
    std::vector<Animal>  getAnimals();
};

#endif

and Zoo.cpp :

#include "Zoo.h"

** REMOVED : include Animal.h

//#include "Animal.h"

Zoo::Zoo(std::string  n) // no importance, n is the name of the zoo
    {
        zooName = n;

** REMOVED : **

        //std::vector<Animal> animals(); // <<< REMOVED
    }

** ADDED : const & **

void Zoo::addAnimal(Animal const &a)    // <<<< const added
    {
        animals.push_back(a); // add an animal to the zoo
    }

std::vector<Animal> Zoo:: getAnimals()
    {
        return animals;
    }

And Animal.h

#ifndef ANIMAL_H
#define ANIMAL_H
#include <string>

** ADDED : forward declaration of Zoo **

class Zoo;

** REMOVED : include file

// #include "Zoo.h"    

class Animal
{
  private:

** CHANGED : pointer to Zoo **

    Zoo * zoo; // in which zoo   <<< CHANGED TO A POINTER
    std::string nom;  // name of an animal

  public:

** CHANGED : pointer to Zoo AND REMOVE & after string**

    // Animal(Zoo z, std::string & n); 
    Animal(Zoo * z, std::string n); 
    std::string toString();
};

#endif

And Animal.cpp :

#include "Animal.h"

** ADDED : include "Zoo.h"**

#include "Zoo.h"
#include <sstream> // ADDED TO CONVERT number to string

** CHANGED : pointer to Zoo AND REMOVED & after string**

//Animal::Animal(Zoo  z, std::string & n) // 
 Animal::Animal(Zoo * z, std::string  n) // 
    {  zoo = z; nom= n;
    }

std::string Animal::toString()
    {

** CHANGED : to justify the use of Zoo inside Animal **

    std::string msg1 (" among ");
    std::string msg3 (" other animals") ;
    // to convert number to string
        std::ostringstream chaine;
        chaine << zoo->getAnimals().size();
    std::string msg2(chaine.str());

    return (name+msg1+msg2+msg3);

    }

EDIT3 - And a main function to test these classes :

 #include <iostream>
 #include "Animal.h" 
 #include "Zoo.h"
 int main()
{
    std::string zooName("BigZoo");
    Zoo z(zooName);
    std::string nom;

    std::cin >> nom;
    while (nom.compare("*") != 0)
    {

**CHANGED : 2 lines deleted and 1 line added

    //    Animal a(&z,nom);
    //    z.addAnimal(a);
        z.addAnimal(Animal(&z, nom));
        std::cin >> nom;
    }

    for (unsigned int i=0;i<z.getAnimals().size(); i++)
    { // for each animal of the zoo
        std::cout << z.getAnimals().at(i).toString() << std::endl;
    }

    return 0;
}

And a test to end :

>max 
>bill
>jumbo
>sheeta
>*
 max among 4 other animals
 bill among 4 other animals
 jumbo among 4 other animals
 sheeta among 4 other animals

well done, stackoverflow is really great !!! thanks again


=====================================

FINAL HEADER CODE

=====================================

/* Zoo.h */
#ifndef ZOO_H
#define ZOO_H
#include <vector>
#include <string>
#include "Animal.h"

class Zoo
{
  private:
    std::string zooName;
    std::vector<Animal> animals;  // liste of animals
  public:
    Zoo(std::string  n);
    void addAnimal(Animal const & a);
    std::vector<Animal>  getAnimals();
};

#endif


/* Animal.h */

#ifndef ANIMAL_H
#define ANIMAL_H
#include <string>

class Zoo;

class Animal
{
  private:
    Zoo *zoo ; // in which zoo
    std::string name;  // name of an animal

  public:
    Animal(Zoo *z, std::string  n);
    std::string toString();
};

#endif

Upvotes: 0

Views: 1355

Answers (3)

Randolf
Randolf

Reputation: 125

Made some corrections and compiled the code, Animal.h,

#ifndef ANIMAL_H
#define ANIMAL_H
#include <string>

class Zoo;
class Animal
{
  private:
    Zoo& zoo; // in which zoo
    std::string nom;  // name of an animal

  public:
    Animal(Zoo &z, std::string & n);
    std::string toString();
};

#endif

Zoo.h,

#ifndef ZOO_H
#define ZOO_H

#include <vector>
#include "Animal.h"
class Animal; 

class Zoo
{
  private:
    std::vector<Animal> animals;  // list of animals
  public:
    Zoo();
    void addAnimal(Animal & a);
    std::vector<Animal>  getAnimals();
};

#endif

Animal.cpp,

#include "Animal.h"

Animal::Animal(Zoo & z, std::string & n) : zoo(z), nom(n)
    { /* zoo = z; nom= n;*/
    }

std::string Animal::toString()
    {
        return nom;
    }

Zoo.cpp,

#include "Zoo.h"

Zoo::Zoo()
    {
        std::vector<Animal> animals(); // list of animals
    }

void Zoo::addAnimal(Animal &a)
    {
        animals.push_back(a); // add an animal to the zoo
    }

std::vector<Animal> Zoo:: getAnimals()
    {
        return animals;
    }

Main.cpp

   Zoo z;
   std::string nom("sheeta");
   Animal a(z,nom);

Changes are, 1) Zoo zoo; to Zoo& zoo; -> I think here you need to store the reference of the zoo than creating a new object, correct?

2) Correct the header inclusions to resolve the compilation errors as in the code below.

Upvotes: 0

Bo Persson
Bo Persson

Reputation: 92341

Q1. When declaring a vector<Animal> the Animal class has to be a complete class. Unlike Java, C++ stores the member elements by value and not by reference.

Q2 & Q3. Zoo z(); declares a function taking no parameters and returning a Zoo. So you try to use a function name in the constructor of Animal. Doesn't work.

Q4. Creating a temporary parameter works, provided the addAnimal takes a const reference to the parameter - void addAnimal(Animal const& a);.

And, easy on the getters! Returning a copy (cloning?) of all the animals from the Zoo seems a bit much. What is the use of getAnimals, other than creating a new zoo?

Also, real animals at a zoo generally don't know which zoo they belong to. So having a reference in the Animal object seems a bit odd.

Also (2), std::vector<Animal> animals(); is another function declaration, just like Zoo z();. You have to watch out for those.

Upvotes: 1

Werner Henze
Werner Henze

Reputation: 16771

vector<Animal> requires Animal to be a complete type at this point, so you need to change Zoo.h to #include "Animal.h". In Animal.h you can forward declare class Zoo; But you also need to change the Animal member zoo to a reference Zoo &zoo;.

Upvotes: 1

Related Questions