Seguro que esta solución ya está implementada por ahí pero yo no la he encontrado.
Para ponernos en antecedentes, tenemos una clase Thread en C++ que representa hilos de ejecución. Esta clase tiene un método execute() que es el que realmente ejecuta el hilo. De esta se puede heredar para implementar dicho método y que este se ejecute en un hilo independiente. La clase Thread cuenta con métodos protegidos (protected) para que sólo los usen las clases derivadas.
Pero, además de derivar la clase Thread, esta clase tiene una clase anidada llamada Thread::Worker que también se puede derivar con la ventaja de que se pueden pasar muchas instancias de Thread::Worker a una sola instancia de la clase Thread para que las ejecute.
El problema surge cuando desde la clase Thread::Worker, al igual que desde las subclases de Thread, se desea acceder a los métodos protegidos (que, en teoría, son sólo para ayudar en la funcionalidad de las clases derivadas). Inicialmente esto no es posible ya que no se puede acceder a métodos protegidos de una clase si no es desde la propia clase o desde clases derivadas, no importa si son clases anidadas, a efectos de protección, son como clases externas.
Con algunas omisiones de código, la implementación de las clases es la siguiente:
class Thread {
[...]
public:
class Worker {
protected:
Thread * const getOwnerThread() const;
public:
virtual void execute();
};
private:
Worker* _worker;
protected:
bool isThreadRunning();
virtual void execute();
public:
Thread(Worker* worker) : _worker(worker) {
_worker->_owner = this;
}
[...]
};
class MyThread : public Thread {
protected:
virtual void execute() {
while(isThreadRunning()) {
}
}
};
class MyWorker : public Thread::Worker {
protected:
virtual void execute() {
while(getOwnerThread()->isThreadRunning()) {
}
}
}
int
main() {
MyThread* mt = new MyThread();
Thread* t = new Thread(new MyWorker());
return 0;
}
La funcionalidad deseada es que la clase Thread::Worker se comporte como la clase Thread cuando se hacen clases derivadas de ella, para poder usar la funcionalidad de gestión de la clase Thread desde la clase Thread::Worker (las funciones protegidas).
Pero al compilador no le gusta que se llamen funciones protegidas desde clases externas aunque sean anidadas.
La solución pasa por crear un puntero a método en la clase anidada que sea asignado a la función que hay que ejecutar. Cuando la instancia de la clase Thread::Worker es añadida a la instancia de la clase Thread, esta última asigna las direcciones de memoria de sus métodos a las variables internas de la clase Thread::Worker, con lo que una llamada mediante dichos punteros funcionará sin problemas y ejecutará el método protegido de la clase Thread desde la clase externa Thread::Worker.
La implementación sería, más o menos de la siguiente forma:
class Thread {
public:
typedef bool (Thread::*ThreadMethod1)();
class Worker {
private:
ThreadMethod1 _isThreadRunning;
protected:
bool isThreadRunning() {
return (getOwnerThread()->*_isThreadRunning)();
}
};
Thread(Worker* worker) : _worker(worker) {
_worker->_owner = this;
_worker->_isThreadRunning = &Thread::isThreadRunning;
}
}
Con esto se consigue que la clase Thread::Worker se comporte, a efectos de derivación de clases, como si se derivase de la clase Thread. Hay que tener en cuenta que las clases derivadas de la clase Thread::Worker siempre se tienen que añadir a una instancia de la clase Thread para todo funcione correctamente.
Como es bastante difícil interpretar código fuente desde esta lectura, he preparado una pequeña aplicación en C++ para mostrar el funcionamiento de este tipo de solución.
Espero que esto sirva para alguien a parte de mi. Y si lo encontráis por algún otro sitio me lo comentáis, porque como he dicho al principio, seguro que no soy el primero en hacerlo.