Fonctions membres virtuelles et pointeur intelligent

Le problème exposé dans ce sujet a été résolu.

Bonjour,

Je bloque un peu sur un code qui me semble pourtant assez simple. J’ai la classe suivante :

class Company
{
public:
    void add_employee(Employee &&employee) // La définition n'est pas là, c'est juste pour simplifier
    {
        employees_.push_back(std::make_unique<Employee>(std::move(employee)));
    }

private:
    std::vector<std::unique_ptr<Employee>> employees_;
};

Et la classe Employee suivante :

class Employee
{
public:
    Employee(double salary=1200);
    virtual ~Employee();

    virtual double compute_salary() const;
    virtual void display() const;

protected:
    double salary_;
};

Et j’ai 6 classes qui héritent de Employee. Mon but est de pouvoir avoir dans mon vecteur Company::employees_ toute sorte d’employé dont des classes filles.

Le problème est que dans la méthode suivante par exemple :

void Company::display_employee_salary() const
{
    for (auto &&employee : employees_) {
        std::cout << employee->get_firstname() << " " << employee->get_lastname() << ": ";
        std::cout << employee->compute_salary() << " €\n";
    }
}

La méthode compute_salary appelée est celle de la classe employé et non celle d’une des classes filles. Est-ce que c’est parce que j’utilise un pointeur unique_ptr ?

Merci pour votre aide

Non, c’est parce que tu as fait des erreurs ;)

En fait, tout découle du non respect des sémantiques de classe. Ici, ta classe Employee a une semantique d’entité (puisque impliquée dans un héritage). Donc cette classe ne doit pas être copiable (l’heritage et la copie font pas bon ménage, comme tu le vois).

employees_.push_back(std::make_unique<Employee>(std::move(employee)));

En fait, dans cette ligne, tu as un objet (polymorphique, qui est un type dérivé de Employee) et tu crées un nouvel objet avec make_unique. Donc tu as 2 objets maintenant :

  • faire un move + rvalue ref, pour au final finir par une copie, c’est pas top pour l’optimisation (j’imagine que le but du move et &&, c’est d’optimiser)
  • l’objet dans le vector est forcément de type Employee ! puisque tu appelles make_unique<Employee>. Donc tu perds forcément le type concret lors de la copie (voilà le problème de l’héritage et la copie)

Pour la solution.

  1. corriger ce probleme de semantique de classe, en interdisant la copie
  2. tu as un objet Employee que tu passes par rvalue ref. Est-ce parce qu’il est sur la Pile ? Si c’est le cas, tu as forcement un gros problème, puisque cet objet a deja un ownership (la Pile) et qu’il n’est pas transférable. Donc obligatoirement une copie pour le mettre dans un vector (avec ou sans unique_ptr).

La solution est de creer directement un unique_ptr puis de faire le transfert de ce pointeur (via && et move, comme tu l’as fait), soit de creer directement l’objet dans add_employee (pas pas copie, mais directement avec les arguments du constructeur de Employee)

Hors sujet : initialise ta variable salary_ directement lors de sa déclaration

+2 -0

Désolé pour le retard de cette réponse.

Merci pour ton aide, ça a l’air de fonctionner, j’ai encore du mal avec la sémantique de mouvement… :euh:

Voici comment j’ai procédé :

// Classe Company :
void add_employee(std::unique_ptr<Employee> &&employee)
{
    employees_.push_back(std::move(employee));
}

// main :
ipsa.add_employee(std::make_unique<Seller>(Seller{ "foo", "bar", 36, 10 }));
+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte