2017-05-17 1 views
3

Pourquoi l'utilisation de l'opérateur d'affectation sur un pointeur déréférencé vers une interface purement abstraite n'est-elle pas une erreur de compilation? Quand cela pourrait-il être utile? Il semble que cela ne peut que conduire à des bugs subtils, comme je l'ai souligné ci-dessous. Pour avoir un objet globalement accessible, qui implémente une interface, avec une valeur par défaut, que je puisse par la suite surcharger, dois-je utiliser un handle (pointeur vers un pointeur ou un pointeur vers un std) :: unique_ptr), ou y a-t-il une autre approche?Pourquoi l'utilisation de l'opérateur d'affectation sur un pointeur déréférencé pour interfacer n'est-elle pas une erreur du compilateur?

#include <iostream> 

class Interface { 
public: 
    virtual int Value() = 0; 
}; 

class Implementation : public Interface { 
public: 
    Implementation(int value) : value(value) {} 
    int Value() override { 
    return value; 
    } 
    int value; 
}; 

// Set default value 
Interface* object = new Implementation(1); 
Implementation* object2 = new Implementation(2); 

int main() { 
    // Why is this line not a compiler error? 
    *object = Implementation(3); // Try to override default value 
    *object2 = Implementation(4); // Override default value 
    // This outputs "14", not "34", why? 
    std::cout << object->Value() << object2->Value(); 
    return 0; 
} 

Pour contourner ces problèmes, ainsi que de permettre le réglage de la substitution de la valeur par défaut dans les tests unitaires, je suis allé avec l'approche suivante.

// Set default value 
static std::unique_ptr<Interface> object(new Implementation(1)); 
void SetObject(std::unique_ptr<Interface> obj) { 
    object.reset(obj.release()); 
} 

int main() { 
    SetObject(std::make_unique<Implementation>(2)); // Override default value 
    std::cout << object->Value(); 
    return 0; 
} 

Répondre

5

objets C++ par défaut obtenir un procédé operator= généré par le compilateur. Cet opérateur applique simplement operator= à chacune des variables membres, et il est pas virtuel. Cela signifie qu'il fonctionnera avec les membres du type statique du pointeur déclaré. Puisque Interface n'a aucun membre, aucun membre ne sera copié. Implementation a un membre, de sorte que ce membre sera copié.

+0

Je vois. Donc le vrai problème était mon affirmation selon laquelle "Interface" était une "pure interface abstraite". Ce n'est pas vrai. Pour que cela soit le cas, j'aurais besoin d'ajouter un peu plus de choses comme la suppression des fonctions par défaut pour qu'il y ait l'erreur du compilateur. "Interface et opérateur = (const Interface &) = delete;" – AffluentOwl

+0

@AffluentOwl exactement correct. –

+0

Existe-t-il un moyen de rendre l'opérateur d'assignation virtuel sur l'interface, et permettez-lui d'être surchargé de telle manière que je puisse obtenir la sortie finale de ma fonction principale à "34"? – AffluentOwl