The best alternative solution for making constant inheritance (or read-only inheritance or you call whatever you want) in C++ that I came up with so far | |
03/23/2014 In this page, I am posting the best solution toward constant inheritance in C++ that I came up with so far. I believe many people are trying but failing to make a const inheritance in C++. I think some call it read-only inheritance. You can call it whatever you want. I'm calling it const inheritance. I spent good amount of time searching for a solution, but I couldn't find a good solution. What I want to do is this: class YsShell { public: // Something useful }; class YsShellExt : private YsShell { public: operator const YsShell &() const; }; YsShellExt is privately derived from YsShell. So, I want to mostly prohibit access to YsShell through YsShellExt. But, I want to open constant access to YsShell by the conversion operator. However, C++ specification apparently doesn't allow you to do it. If you write like: void SomeFunction(const YsShell &shl); YsShellExt shlExt; SomeFunction(shlExt); The compiler will give you an error. It won't look at the conversion operator that is explicitly declared as public. The C++ rule apparently does not allow automatic conversion to the base class if the inheritance is private or protected. Unless you come up with a trick, the only way to pass a const YsShell reference to the function is through static cast: YsShellExt shlExt; SomeFunction((const YsShell &)shlExt); // Possible, but want to avoid static cast. But, I want to avoid static cast. It will disable type check. The point is I want to avoid typing (const YsShell &) here. I want the C++ compiler automatically find a valid conversion and give it to the function.
I have tried to find a good solution myself several times in the past with no success. But, I recently came up with the best closest solution through the converter class. I can make converter classes in YsShellExt class like: class YsShell { public: // Something useful }; class YsShellExt : private YsShell { public: class Converter { public: YsShellExt *shl; operator const YsShell &() const { return *(const YsShell *)shl; } operator YsShellExt &() const { return *shl; } }; class ConstConverter { public: const YsShellExt *shl; operator const YsShell &() const { return *(const YsShell *)shl; } operator const YsShellExt &() const { return *(const YsShellExt *)shl; } }; inline Converter Conv(void) { Converter conv; conv.shl=this; return conv; } inline ConstConverter Conv(void) const { ConstConverter conv; conv.shl=this; return conv; } }; When I want to pass to a function a YsShellExt object as a const YsShell &, I can write: YsShellExt shlExt; SomeFunction(shlExt.Conv()); // No static cast. Compiler will catch if the receiving type is incompatible. A Converter object can be automatically casted into const YsShell &, const YsShellExt &, or YsShellExt &. If shlExt is const, a ConstConverter class will be used and can be automatically casted into const YsShell & or const YsShellExt &. The compiler will pick the right conversion. I avoid static cast here. A Converter object is as big as a pointer, and the time for copying it is negligible. If you want to go strict RIAA, you can also pass the this pointer to a Converter object through the constructor, but I like my way of writing because it simply keeps it POD.
|
|