Niedawno przełączyłem się z Java i Ruby na C++, i ku mojemu zdziwieniu muszę przekompilować pliki, które używają publicznego interfejsu, gdy zmienię sygnaturę metody metoda prywatna, ponieważ również prywatne części znajdują się w pliku .h.utrzymanie prywatnych części poza nagłówkami C++: czysta wirtualna klasa bazowa vs pimpl
Szybko wymyśliłem rozwiązanie, które, jak sądzę, jest typowe dla programisty Java: interfejsy (= czyste wirtualne klasy bazowe). Na przykład:
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);
}
Jedynym kłopotem tutaj jest to, że nie mogę używać new
i musi zamiast zadzwonić BananaTree::create()
. Nie sądzę, żeby to był naprawdę problem, zwłaszcza, że i tak spodziewam się dużo używać fabryk.
Teraz, mędrcy sławy C++, jednak wymyślili inne rozwiązanie, pImpl idiom. Z tym, jeśli rozumiem go poprawnie, mój kod będzie wyglądać następująco:
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);
}
oznaczałoby to trzeba zaimplementować dekorator styl przekazywania dla każdej publicznej metody BananaTree
, w tym przypadku getBanana
. To brzmi jak dodatkowy poziom złożoności i wysiłku w zakresie konserwacji, których wolę nie wymagać.
Na pytanie: co jest złego w przypadku podejścia opartego na czystej wirtualnej klasie? Dlaczego podejście pImpl jest o wiele lepiej udokumentowane? Czy coś ominąłem?