Dealing with an opaque objects hierarchy

 

"even monoliths can have a family"

2012 by Arnaud Sintès

 

Keywordsarchitecture, c++, interface, multiple-inheritance, template specialization

 

As an introduction note, please refer to my previous document about the opaque objects and the specialized template interfaces concept.

http://www.silentbreed.com/opaque/

  

 

Description: http://nicomel.my.tripper-tips.com/photo/ahu-tongariki...les-15-moai-700-111097.jpg

 

We’ve seen before the interest to add multiple interfaces access to your object to keep the full control over the user’s visibility of its content.

It was called full opaque objects (http://www.silentbreed.com/opaque/).

 

This is great, but you may be afraid to generalize this approach of object implementation by considering a classic object hierarchy with a lot of parent/child dependencies which will have to deal with crossed access over all these objects interfaces.

 

Let’s consider a simple class hierarchy were two objects (‘A’ and ‘B’) have to be accessed in read only mode at some point and in read/write mode somewhere else.

 

Writing the ‘B’ class with its interfaces is easy:

// ----------

// interface access types

class Read;

class ReadWrite;

       

 

// ----------

// 'B' templatized interfaces declaration

template< class T = void > class IB {};

 

 

// Read interface access to 'B'

template<>

__interface IB< Read > {

       const void GetSomething() const;

};

 

 

// Read/Write interface access to 'B'

template<>

__interface IB< ReadWrite > {

       const void GetSomething() const;

       void SetSomething();

};

 

 

// ----------

// 'B' object definition

class B sealed

       : public IB< Read >

       , public IB< ReadWrite >

{

private: // IB< Read, ReadWrite >

       const void GetSomething() const sealed {}

       void SetSomething() sealed {}

};

 

 

The problem we have to consider is how to get the read only access interface of ‘B’ through the read only access interface of ‘A’, and how to get the read/write access interface of ‘B’ through the read/write access interface of ‘A’.

 

To be more clear, we hope to get a single method “GetB()” in both read only and read/write interfaces of ‘A’ to get a const IB< Read > interface in the first case and a IB< ReadWrite > interface in the second one.

// ----------

// interface access types

class Read;

class ReadWrite;

       

 

// ----------

// 'A' templatized interfaces declaration

template< class T = void > class IA {};

 

 

// Read interface access to 'A'

template<>

__interface IA< Read > {

       // through the IA< Read > interface, we want GetB() to return a const IB< Read > interface

       const IB< Read > & GetB() const;

};

 

 

// Read/Write interface access to 'A'

template<>

__interface IA< ReadWrite > {

       // through the IA< ReadWrite > interface, we want GetB() to return a IB< ReadWrite > interface

       IB< ReadWrite > & GetB() const;

       void SetSomething();

};

 

 

The answer is... it’s fucking trivial, thank you C++! J

 

You will just have to define a single sealed “GetB()” method in your inherited class which will return the base ‘B’ class reference, then the compiler smartly collapse both definitions into the implementation thanks to the inheritance magic.

// ----------

// 'A' object definition

class A sealed

       : public IA< Read >

       , public IA< ReadWrite >

{

private:

       // the two interfaces definition will collapse to the same implementation

       B & GetB() const sealed { return m_b; }

       void SetSomething() sealed {}

 

private:

       mutable B m_b;

};

 

 

Let’s demo this:

void Demo() {

 

       // get a Read interface of a new 'A' object

       IA< Read > & A_R = *new A();

       // GetB() will return the const Read version of 'B'

       const IB< Read > & B_R = A_R.GetB();

       B_R.GetSomething();

 

       // get the Read/Write interface of a new 'A' object

       IA< ReadWrite > & A_RW = *new A();

       // GetB() will return the Read/Write version of 'B'

       IB< ReadWrite > & B_RW = A_RW.GetB();

       B_RW.GetSomething();

       B_RW.SetSomething();

}

 

 

That’s all folks, hope this help!

 

Description: http://whattheeff.com/wp-content/uploads/2012/03/hipster-moai-333x266.jpg