|
Information Hiding Tricks in C++
Submitted by |
As most object-oriented programmers know, information hiding is one of the most
important things in OOP. It also causes problems, because there is cases when
some other classes than deviced classes should have access to the hidden
information. We still don't want this information be available through public
interface and declaring friend classes isn't nice option either, because it
strings some nasty dependencies between components. So what can we do? Here I
present two of tricks that can be used, but should be used with caution:
1) If classes share same base class and you need to access protected base class
members of a cross-class. Example follows:
class Base
{
protected:
void foo() {}
};
class A: public Base {};
class B: public Base
{
public:
void bar(A &a_) {a_.foo();}
}; |
The following piece of code won't compile, because access to protected
interface of a cross-class isn't allowed. What you can do, however, is that
you cross-cast the passed argument to the type of the class where from you
try to access the protected interface:
class B: public Base
{
public:
void bar(A &a_) {((B&)a_).foo();}
};
Example of the usage:
int main(void)
{
A a;
B b;
b.bar(a);
return 0;
} |
Naturally there are risks in cross-casting as well as down-casting whereto
this trick can also be applied on. For instance if you change the
inheritance scheme of a cross-class (for instance change inheritance of A
from Base to Base2), this would play havoc on your code if you forget to
change the interface to match the new purpose. Also if you accidently call
other than base class members after the typecasting it will cause damage.
I faced need for this trick when I designed state handling framework for my
3D engine. Each different state as well as state controller class are derived
from StateBase class. StateBase-class has derived by using protected
inheritance from ListItem-class which implements implicit list accessors and
mutators. Protected inheritance is used because I don't want to expose state
list to consumers and prevent them writing code which relies that states
are actually present in a list. Still, access to the list is required from
the state controller and different states.
2) Another useful trick according information hiding I found when applying
object factory pattern. In my 3D engine models (meshes) are created from
vertex array and they need some low level access to the vertex array, which
I don't want to expose to consumers (for instance querying IDirect3DDevice7
interface in D3D implementation). These two classes got no relations in
inheritance scheme whatfor I can't use the first trick.
However, because vertex array takes care of model creation, I can pass
abstract access base class, which publicly declares required low level
access and use private inheritance to inherit vertex array from it. The
access interface is implemented in private section of vertex array ensuring
that no other classes than created models can access it. By reguesting
access base interface in model constructors I also prevent explicit
instantiation of model classes. And example follows:
class AccessBase
{
public:
virtual void foo()=0;
protected:
~AccessBase() {}
private:
void operator=(const AccessBase&); // no implementation
};
class A
{
public:
A(AccessBase &access_) {m_access=&access_;}
void bar() {m_access-foo();}
private:
A(const A&); // no implementation
void operator=(const A&); // no implementation
AccessBase *m_access;
};
class Factory: private AccessBase
{
public:
A *create() {return new A(*this);}
private:
void foo() {}
};
Example of the usage:
int main(void)
{
Factory fact;
A *a=fact.create();
delete a;
return 0;
} |
If we look for drawback of this approach, it's obvious that we need to
declare extra interface class which allows the access.
If you wonder what are these "// no implementation" lines, they are just
added to prohibit incorrect use of the interface allowed by auto generation
of those members.
|
The zip file viewer built into the Developer Toolbox made use
of the zlib library, as well as the zlibdll source additions.
|