S tim public const nemáš IMHO pravdu. Jeden z cílů, proč je to tak udělané je, aby uživatelé nepoužívali místo veřejných a zaručených metod střeva. Protože střeva se můžou klidně změnit. Používáním "nedokumentovaných" střev si zakládáš na pořádnej problém... a protected proti tomu chrání.... (nicméně někdy, např. pro účely ladění, by se to hodilo, to zas jo).
public const jsem myslel místo
public:
const std::string& getName() const {
return this->name;
}
protected:
std::string name;
V tomhle případě by name mohlo být dokumentované a const přístupné a nemusel bych psát getter. Na druhou stranu nechci, aby mi to někdo měnil, a const std::string name použít nemohu, protože by to znemožnilo přiřazování.
Stejně tak private má svůj smysl. Pokud máš nějakou vnitřní stavovou proměnou a chceš zajistit, aby Ti ho žádný potomek obejktu nerozbil, tak to použiješ. Něco podobného je i v o dost mladší javě (final).
Zatím jsem
nikdy nepotřeboval něco skrývat před potomky (a ani před programátory, kteří mé knihovny používali). Stejně tak jsem nepochopil, k čemu je dobrý final, než naštvat programátora, který přijde po vás, že si to nemůže podědit a upravit, ale musí si to napsat celé znovu, když se vaše úžasná třída přesně nehodí jeho potřebám.
Pokud si to potomek rozbije, je to jeho zodpovědnost a jeho problém; pokud potomek sáhne do nealokované paměti, tak celý program taky spadne a je to problém toho potomka. Spíše mám opačné zkušenosti — už několikrát se mi stalo, že by se mi hodilo v konkrétním případě zasáhnout do vnitřní stavové proměnné v poděděném objektu (často cizím) a nešlo to, takže jsem tam před #include musel dát
#define private protected
Co se týče sahání do nedokumentovaných střev, tak s tím bych problém neviděl, moje objekty nedokumentovaná střeva nemají a když se nějaká střeva změní, tak se holt rozbije program (nebo překlad) stejně jako když se změní veřejné metody (stejně i změna private memberů znamená novou verzi ABI).
Třeba STL má implementation specific střeva, ale to neznamená, že by se na ně nesmělo sahat. Napadá mě jedno řešení: některá střeva označit, že jsou implementation specific, a když se je pokusíte použít implicitně (dědičností), tak by program vyvolal varování (nebo klidně i error), ale explicitně (se jménem objektu) by použít šly, takže by pořád bylo možné je upravovat:
class SomeObject
{
protected:
specific std::string _data;
};
class Inherited
: public SomeObject
{
public:
void someFunc()
{
this->_data = "a"; // Varování, použito implicitně
this->SomeObject::_data; // OK, použito explicitně
}
};