Recientemente he cambiado de nuevo desde Java y Ruby a C++, y para mi sorpresa me tienen que volver a compilar los archivos que utilizan la interfaz pública cuando cambio el método de la firma de un método privado, porque también las partes privadas están en el archivo .h.mantenimiento de partes privadas fuera C++ cabeceras: pura clase base virtual vs pimpl
rápidamente me ocurrió una solución que es, supongo, típico de un programador de Java: interfaces (= clases base virtuales puras). Por ejemplo:
BananaTree.h:
class Banana;
class BananaTree
{
public:
virtual Banana* getBanana(std::string const& name) = 0;
static BananaTree* create(std::string const& name);
};
BananaTree.cpp:
class BananaTreeImpl : public BananaTree
{
private:
string name;
Banana* findBanana(string const& name)
{
return //obtain banana, somehow;
}
public:
BananaTreeImpl(string name)
: name(name)
{}
virtual Banana* getBanana(string const& name)
{
return findBanana(name);
}
};
BananaTree* BananaTree::create(string const& name)
{
return new BananaTreeImpl(name);
}
El único inconveniente aquí es que no puedo usar new
, y en su lugar debe llamar BananaTree::create()
. No creo que eso sea realmente un problema, especialmente porque espero usar muchas fábricas de todos modos.
Ahora, los sabios de la fama C++, sin embargo, ocurrió otra solución, el pImpl idiom. Con eso, si he entendido bien, mi código se vería así:
BananaTree.h:
class BananaTree
{
public:
Banana* addStep(std::string const& name);
private:
struct Impl;
shared_ptr<Impl> pimpl_;
};
BananaTree.cpp:
struct BananaTree::Impl
{
string name;
Banana* findBanana(string const& name)
{
return //obtain banana, somehow;
}
Banana* getBanana(string const& name)
{
return findBanana(name);
}
Impl(string const& name) : name(name) {}
}
BananaTree::BananaTree(string const& name)
: pimpl_(shared_ptr<Impl>(new Impl(name)))
{}
Banana* BananaTree::getBanana(string const& name)
{
return pimpl_->getBanana(name);
}
Esto significa que tenga que aplicar un decorador método de reenvío de estilo para cada método público de BananaTree
, en este caso getBanana
. Esto suena como un nivel agregado de complejidad y esfuerzo de mantenimiento que prefiero no requerir.
lo tanto, ahora la pregunta: ¿Qué está mal con el enfoque de clase virtual pura? ¿Por qué el enfoque de pImpl está mucho mejor documentado? ¿Yo me perdí algo?