2010-12-31 22 views
36

Necesito usar un operador virtual < <. Sin embargo, cuando trato de escribir:Haciendo operador << virtual?

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

me sale el error del compilador

de error 1 error C2575: 'operador < <': sólo funciones miembro y las bases pueden ser virtuales

¿Cómo puedo activar este operador virtual?

Respuesta

63

El problema con esta configuración es que el operador < < que definió anteriormente es una función libre, que no puede ser virtual (no tiene un objeto receptor). Para hacer que la función sea virtual, debe definirse como un miembro de alguna clase, lo cual es problemático aquí porque si define operador < < como miembro de una clase, los operandos estarán en el orden incorrecto:

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

significa que

MyClass myObject; 
cout << myObject; 

no se compilará, pero

MyClass myObject; 
myObject << cout; 

será legal.

Para solucionar esto, puede aplicar el Teorema Fundamental de la Ingeniería de Software: cualquier problema puede resolverse agregando otra capa de indirección. En lugar de hacer operador < < virtual, considerar la adición de una nueva función virtual de la clase que tiene este aspecto:

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

A continuación, defina operador < < como

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

De esta manera, el operador < < la función libre tiene el orden correcto de parámetros, pero el comportamiento del operador < < se puede personalizar en subclases.

Espero que esto ayude!

+0

gracias es muy útil. Pensé en esta solución, pero pensé que tal vez Hay otra manera en que no sé que sea más fácil de implementar. –

+4

* "cualquier problema puede resolverse agregando otra capa de direccionamiento indirecto" * - recuerde, cualquier problema excepto el problema de demasiadas capas de indirección;) – Kos

+12

@Kos: No, no. Siempre y cuando haya declarado 'indirección sin signo;', solo tiene que seguir agregando más y más indirección y el problema se resolverá solo cuando pase el mouse sobre –

2

Parece que realmente desea proporcionar funcionalidad de salida para una jerarquía de clases, y si es así, puede proporcionar un friend operator << que llama a una función 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 
    } 
}; 

también detalló en el C++ FAQ

25

Se define el operador de < < llamar a un método de impresión virtual:

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; 
     } 
} 
+1

, probablemente significó 'data.print (str);' –

+0

Además Para el comentario de @Gen, la función virtual pura necesita protección para que las clases que no sean amigos puedan implementarla. –

+1

@Daniel Trebbien: Usted podría simplemente dejarlo como privado y aún será implementable. Pero estoy de acuerdo protegido es probablemente una buena idea. –

-2

La técnica que utilizo es funcionalmente idéntico a lo que otros han mencionado, excepto que hago que la función de "impresión" virtual sea una sobrecarga de función miembro del operador >>:

class my_class 
{ 
protected: 
    virtual std::ostream& operator>>(std::ostream& os_) const 
    { 
     // print *this to `os_` 
     return os_; 
    } 

public: 
    friend inline std::ostream& operator<<(std::ostream& os, const my_class& mc) { 
     return (mc >> os); 
    } 
}; 

Esta es la idea detrás de una plantilla de utilidad de uno de mis proyectos de código abierto. Ver: https://libnstdcxx.googlecode.com/svn/trunk/doc/html/classnstd_1_1basic__printable.html

Cuestiones relacionadas