Hints on hiding alternative implementations?

Hi, I'm an old fart in (C-)programming, but quite nooby in today's C++.
(Did little something with C++ at the end of of 80's.)

My question: what would be a good mechanism of hiding alternative
implementations in C++?

What I was thinking was a class - say "InOutClass".
The I/O would be done by passing the object of InOutClass to
other classes that need to input or output something.

Something like:

1
2
3
4
5
6
7
8
9
10
class InOutClass
{
private:
    Context context;
public:
    int Initialise();
    int Write();
    int Read();
    int cleanup();
};


Then there could be different implementation classes, say
HTTP, file, RS232, ...

All the other classes see is InOutClass.

It looks like template needs that parameters visible in classes that use
the InOutClass and Inheritance goes the other way: specific class methods could be implemented in the general class.

In this case the general class methods should be implemented in a specific class.

Last edited on
Functions Initialize and cleanup are better suited to the constructor(s) and destructor respectively.

I think you mean interface? Look up the concept of interfaces, then for C++. It can be done with either templates or abstract classes.
This is the purpose of polymorphism
http://www.cplusplus.com/doc/tutorial/polymorphism/
I think this will get you on the right track.
The idea is that the other classes could use:

1
2
3
4
5
6
7
8
int SomeClass::send_data(InOutrClass & iotype, Data & data)
{
    iotupe.initialise();
    ...
   iotype.Write(data);
   ...
   iotype.Cleanup();
}


That is: without knowing anything about the implementation of the InOutClass.
The thing is the Context that can be very different for different implementations, and
may contain other classes.

The idea is that if the implementation class is changed, the rest of the code needs no changes.


I have the bad feeling that C++ compiler wants "SomeClass" to know about the implementation class of the "InOutClass".
Depends on your context (no pun intended). For instance, any of these could be appropriate.

1
2
3
4
5
6
7
8
struct InOutClass // object-oriented interface
{
    virtual ~InOutClass() ;
    virtual int Initialise() = 0 ;
    virtual int Write() = 0 ;
    virtual int Read() = 0 ;
    virtual int cleanup() = 0 ;
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct InOutClass // fully insulating concrete class
{
     InOutClass() ;
     InOutClass( const InOutClass& ) ;
     InOutClass( InOutClass&& ) ;
     InOutClass& operator= ( const InOutClass& ) ;
     InOutClass& operator= ( InOutClass&& ) ;
     ~InOutClass() ;

     int Initialise() ;
     int Write() ;
     int Read() ;
     int cleanup() ;

     private:
        struct opaque_implementation ;
        std::unique_ptr<opaque_implementation> implementation ;
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template< typename CONTEXT, typename RESULT_TYPE = typename CONTEXT::result_type > 
struct InOutClass // generic interface
{
    typedef CONTEXT context_type ;
    typedef RESULT_TYPE result_type ;

    InOutClass( const CONTEXT& = CONTEXT() ) ;
    // ...

    result_type Initialise();
    result_type Write();
    result_type Read();
    result_type cleanup();

    private:
        CONTEXT context;
};
Thanks!

I guess I'll have to check the interface.

I guess I'll also need to do some pondering to figure out the JLBorges' suggestion.

I don't think the polymorphism would solve the problem, when it's about different data:
objects (classes) don't have a signature.

My feeling is that in this case the hybrid nature of C++ becomes visible.
I guess in true O-O language object knows its class.
turboscrew wrote:
I don't think the polymorphism would solve the problem, when it's about different data:
objects (classes) don't have a signature.

My feeling is that in this case the hybrid nature of C++ becomes visible.
I guess in true O-O language object knows its class.
Could you elaborate? Classes DO have a signature and you can always tell what you're dealing with if you want to. (Though if you need to know what kind of object you're dealing with, you're doing something VERY wrong)

What do you mean hybrid nature? C++ is a true OO language and all objects know what kind of class instance they are...
Last edited on
No they don't. RTTI is only available for types with virtual functions.
Which is part of what classifies 'polymorphism'...
What do you mean hybrid nature? C++ is a true OO language and all objects know what kind of class instance they are...


What class do you suppose an object of type long thinks it is? I don't know why people take offense when C++ is called a 'hybrid' language. It is.


Bjarne Stroustrup wrote:
C++ was designed to support data abstraction, object-oriented programming, and generic programming in addition to traditional C programming techniques under these constraints. It was not meant to force one particular programming style upon all users. (TCPL, 3rd ed.)


A language that supports an object-oriented programming paradigm is not necessarily an object-oriented language.
I stand corrected. ;)
If you're looking at using interfaces (the interface pattern) you should also look at the abstract factory pattern and its relatives. This is the standard way of abstracting the creation of objects.

In the Windows world, a good example of this approach is COM. You create classes using class factories (CoCreateInstance tracks down the required class factory and calls its IClassFactory interface to instantiate the required object).

And your InOutClass example isn't a million miles from the standard COM IStream interface.

On the subject of constructor versus init method. I tend to avoid doing heavy work in constructors, preferring two phase construction, as I find this makes it easier to debug things and handle errors. I also find that two phase construction works quite well with the factory approach. For example, the init method does not have to be on the public interface.
Last edited on
Look up the pimpl idiom, it completely hides the implementation. I believe this is JLBorges 2nd suggestion, we use it for all the reasons you stated in your original post.
I'm working with Linux - although it doesn't matter...

There is also another thing why C++ is not full OO language:
It has classes, inheritance and composition, but not general relation in the language level.
(probably due to the fact that there is no common "object"-class every other class is inherited from.)

But hey, that's C++. It is what it is, and it doesn't need to be something else. All true OO languages have to be interpreted, even if bytecode. I guess there are no good mechanisms to imlement fully compilable OO language - at least not yet.

Anyway, lots of thanks for the hints. I'll look into them.

[edit]
By the first glance,the pimpl looks pretty much what have looking for.
[/edit]
Last edited on
Topic archived. No new replies allowed.