2010-05-30 6 views
15

Necesito escribir un programa que implementa el patrón de diseño de visitante. El problema es que la clase de visitante base es una clase de plantilla. Esto significa que BaseVisited :: accept() toma una clase de plantilla como parámetro y como usa 'this' y necesito 'this' para apuntar a la instancia de tiempo de ejecución correcta del objeto, también debe ser virtual.
Me gustaría saber si hay alguna forma de solucionar este problema.necesita una solución de miembro de plantilla virtual

template <typename T> 
class BaseVisitor { 
    public: 
    BaseVisitor(); 
    T visit(BaseVisited *visited); 
    virtual ~BaseVisitor(); 
} 


class BaseVisited { 
    BaseVisited(); 
    template <typename T> 
    virtual void accept(BaseVisitor<T> *visitor) { visitor->visit(this); }; // problem 
    virtual ~BaseVisited(); 
} 
+1

¿Qué pasa con eso? –

+2

no compilará. http://stackoverflow.com/questions/2354210/template-member-function-virtual – yurib

+2

El compilador no aceptará plantillas en funciones virtuales. – Puppy

Respuesta

16

Lo que debe hacer es separar el BaseVisitor.

class BaseVisited; 
class BaseVisitorInternal { 
public: 
    virtual void visit(BaseVisited*) = 0; 
    virtual ~BaseVisitorInternal() {} 
}; 
class BaseVisited { 
    BaseVisited(); 
    virtual void accept(BaseVisitorInternal* visitor) { visitor->visit(this); } 
}; 
template<typename T> class BaseVisitor : public BaseVisitorInternal { 
    void visit(BaseVisited* visited); 
}; 

Si necesita clases derivadas de BaseVisited a ser demasiado con plantilla y pasar sus tipos correctos/sobrecargas para visitar, que está oficialmente muerto.

+0

¡Me ganaste! :-) –

+3

Básicamente, esto es [borrado de tipo] (http://stackoverflow.com/questions/2354210/template-member-function-virtual/2354671#2354671). – sbi

+0

Creo que podría estar oficialmente muerto ... :-P – NargothBond

4

me ocurrió algo ligeramente diferente que DeadMG:

class BaseVisited; 

class IVisitor { 
    public: 
    virtual void visit(BaseVisited *visited) = 0; 
    virtual ~IVisitor(); 
}; 

template <typename T> 
class BaseVisitor : public IVisitor { 
    public: 
    BaseVisitor(); 
    virtual void visit(BaseVisited *visited); 
    virtual ~BaseVisitor(); 
    virtual T result(); 
}; 


class BaseVisited { 
    public: 
    BaseVisited(); 
    virtual void accept(IVisitor *visitor) { visitor->visit(this); }; 
    virtual ~BaseVisited(); 
}; 

El mío tiene una función result() miembro extra que le permite recuperar el resultado de la última visita.

+0

No creo que esto funcione –

4

No puede declarar/definir funciones virtuales con plantilla. La razón es que el mecanismo de despacho virtual debe conocerse cuando el compilador ve la definición de la clase base, pero las plantillas se compilan a pedido.

Con la implementación de vtable común, el problema es que el número de entradas que el compilador debería reservar para la función virtual no está definido (¿cuántas instancias diferentes del tipo puede haber?), Como es el orden de ellas . Si se declara la clase:

class base { 
public: 
    virtual void foo(); 
    virtual int bar(); 
}; 

El compilador puede reservar dos entradas en la viable para los punteros a foo y bar en la viable, y la viable está perfectamente definido sólo por la inspección de la definición de clase. Esto no se puede lograr con funciones de plantilla.

+0

Sé que es imposible y entiendo por qué, mi pregunta era acerca de cómo encontrar una solución que no implique una plantilla de función virtual . gracias de todos modos. – yurib

+0

@Yurib: quiere una solución y aún no ha declarado su problema - Solicité que en un comentario a la pregunta: ¿Qué es lo que realmente desea lograr? Solo ha preguntado sobre una posible solución que no funciona, no sobre cuál es el problema original. –

Cuestiones relacionadas