web-dev-qa-db-fra.com

Rendre l'opérateur << virtuel?

J'ai besoin d'utiliser un opérateur virtuel <<. Cependant, lorsque j'essaie d'écrire:

virtual friend ostream & operator<<(ostream& os,const Advertising& add);

J'obtiens l'erreur du compilateur

Erreur 1 Erreur C2575: 'opérateur <<': seules les fonctions membres et les bases peuvent être virtuelles

Comment puis-je rendre cet opérateur virtuel?

41
inna karpasas

Le problème avec cette configuration est que l'opérateur << que vous avez défini ci-dessus est une fonction libre, qui ne peut pas être virtuelle (elle n'a pas d'objet récepteur). Afin de rendre la fonction virtuelle, elle doit être définie comme membre d'une classe, ce qui pose problème ici car si vous définissez l'opérateur << comme membre d'une classe, les opérandes seront dans le mauvais ordre:

class MyClass {
public:
    virtual ostream& operator<< (ostream& out) const;
};

signifie que

MyClass myObject;
cout << myObject;

ne compilera pas, mais

MyClass myObject;
myObject << cout;

sera légal.

Pour résoudre ce problème, vous pouvez appliquer le théorème fondamental de l'ingénierie logicielle - tout problème peut être résolu en ajoutant une autre couche d'indirection. Plutôt que de rendre l'opérateur << virtuel, pensez à ajouter une nouvelle fonction virtuelle à la classe qui ressemble à ceci:

class MyClass {
public:
    virtual void print(ostream& where) const;
};

Ensuite, définissez l'opérateur << as

ostream& operator<< (ostream& out, const MyClass& mc) {
    mc.print(out);
    return out;
}

De cette façon, l'opérateur << fonction libre a le bon ordre de paramètres, mais le comportement de l'opérateur << peut être personnalisé dans les sous-classes.

J'espère que cela t'aides!

78
templatetypedef

Vous définissez votre opérateur << pour appeler une méthode d'impression virtuelle:

class Base
{
    protected:
        virtual void print(std::ostream& str) const = 0;
    public:
        friend std::ostream& operator<<(std::ostream& str, Base const& data)
        {
            data.print(str);
            return str;
        }
}
34
Martin York

Il semble que vous souhaitiez vraiment fournir une fonctionnalité de sortie pour une hiérarchie de classes, et si c'est le cas, vous pouvez fournir un friend operator << qui appelle une fonction virtual.

class Parent
{
public:
    friend std::ostream& operator<< (std::ostream& os, const Parent& p);
    // ... other class stuff
protected:
    virtual void printMyself(std::ostream& os) const
    {
        // do something if you must, or make this a pure virtual
    }
};

std::ostream& operator<< (std::ostream& os, const Parent& p)
{
    p.printMyself(os);
    return os;
}

class Child : public Parent
{
    // other class stuff...
protected:
    virtual void printMyself(std::ostream os) const
    {
        // whatever you need to do
    }
};

Également détaillé dans le FAQ C++

2
wkl