| 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.
|
|