Multiple inheritance dilemma in C ++

I have problems with the design of my C ++ library. This is a library for reading streams that support a function that I have not found in other "stream" implementations. It doesn't really matter why I decided to start writing. The thing is, I have a thread class that provides two important behaviors through multiple inheritance: compatibility and accessibility.

Shared threads are those that have the shareBlock (size_t length) method, which returns a new thread that shares resources with its parent thread (for example, using the same block of memory used by the parent thread). Available streams are those that are ... well, searchable. Using the seek () method, these classes can search for a given point in the stream. Not all library streams are available and / or searchable.

The stream class, which provides an implementation for finding and sharing resources, inherits interface classes called Seekable and Shareable. It’s good if I know the type of such a stream, but sometimes I may need the function to take a stream as an argument that just performs the search and sharing quality at the same time, no matter what class of the stream it actually is is an. I could do this by creating another class that inherits both Seekable and Shareable and refers to this type, but then I have to make my classes that are simultaneously available for searching and sharing inherited from this class. If more “behavioral classes” like those were added, I would need to make several modifications everywhere in the code,which will soon lead to unreachable code. Is there a way to solve this dilemma? If not, then I absolutely understand why people are not satisfied with multiple inheritance. He almost does the job, but just then, it’s not: D

Any help is appreciated.

- second edit, preferred resolution of the problem -

At first I thought that Managu's solution would be my preferred. However, Matthieu M. came with another, which I preferred because of Managu's: to use boost::enable_if<>. I would like to use Managu's solution if the messages BOOST_MPL_ASSERTwere not so creepy. If there was some way to create instructive messages about compile-time errors, I would definitely do it. But, as I said, accessible methods give creepy messages. Therefore, I prefer a (much smaller) instructive, but cleaner message, created when conditions are boost::enable_if<>not met.

, , , select, :

// SonettoEnableIfDerivedMacros.h
#ifndef SONETTO_ENABLEIFDERIVEDMACROS_H
#define SONETTO_ENABLEIFDERIVEDMACROS_H

#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/array/elem.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/and.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/utility/enable_if.hpp>

/*
    For each (TemplateArgument,DerivedClassType) preprocessor tuple,
    expand: `boost::is_base_and_derived<DerivedClassType,TemplateArgument>,'
*/
#define SONETTO_ENABLE_IF_DERIVED_EXPAND_CONDITION(z,n,data) \
        boost::is_base_and_derived<BOOST_PP_TUPLE_ELEM(2,1,BOOST_PP_ARRAY_ELEM(n,data)), \
                BOOST_PP_TUPLE_ELEM(2,0,BOOST_PP_ARRAY_ELEM(n,data))>,

/*
    ReturnType: Return type of the function
    DerivationsArray: Boost.Preprocessor array containing tuples in the form
            (TemplateArgument,DerivedClassType) (see
                    SONETTO_ENABLE_IF_DERIVED_EXPAND_CONDITION)

    Expands:
    typename boost::enable_if<
            boost::mpl::and_<
                    boost::is_base_and_derived<DerivedClassType,TemplateArgument>,
                    ...
                    boost::mpl::bool_<true> // Used to nullify trailing comma
            >, ReturnType>::type
*/
#define SONETTO_ENABLE_IF_DERIVED(ReturnType,DerivationsArray) \
        typename boost::enable_if< \
                boost::mpl::and_< \
                        BOOST_PP_REPEAT(BOOST_PP_ARRAY_SIZE(DerivationsArray), \
                            SONETTO_ENABLE_IF_DERIVED_EXPAND_CONDITION,DerivationsArray) \
                        boost::mpl::bool_<true> \
            >, ReturnType>::type

#endif

// main.cpp: Usage example
#include <iostream>
#include "SonettoEnableIfDerivedMacros.h"

class BehaviourA
{
public:
    void behaveLikeA() const { std::cout << "behaveLikeA()\n"; }
};

class BehaviourB
{
public:
    void behaveLikeB() const { std::cout << "behaveLikeB()\n"; }
};

class BehaviourC
{
public:
    void behaveLikeC() const { std::cout << "behaveLikeC()\n"; }
};

class CompoundBehaviourAB : public BehaviourA, public BehaviourB {};
class CompoundBehaviourAC : public BehaviourA, public BehaviourC {};
class SingleBehaviourA : public BehaviourA {};

template <class MustBeAB>
SONETTO_ENABLE_IF_DERIVED(void,(2,((MustBeAB,BehaviourA),(MustBeAB,BehaviourB))))
myFunction(MustBeAB &ab)
{
    ab.behaveLikeA();
    ab.behaveLikeB();
}

int main()
{
    CompoundBehaviourAB ab;
    CompoundBehaviourAC ac;
    SingleBehaviourA    a;

    myFunction(ab); // Ok, prints `behaveLikeA()' and `behaveLikeB()'
    myFunction(ac); // Fails with `error: no matching function for
                    // call to `myFunction(CompoundBehaviourAC&)''
    myFunction(a);  // Fails with `error: no matching function for
                    // call to `myFunction(SingleBehaviourA&)''
}

, ( , GCC 3.4.5). . , . , (, , - SFINAE, ). , randomStuff ... ************** garbage ************** BOOST_MPL_ASSERT.

, , . , , , Boost.Preprocessor. , , DerivationsArray 4 SONETTO_ENABLE_IF_DERIVED(). , , , , ++ 1x, ? , , . , .

.

+5
6

boost:: enable_if

// Before
template <class Stream>
some_type some_function(const Stream& c);

// After
template <class Stream>
boost::enable_if<
  boost::mpl::and_<
    boost::is_base_and_derived<Shareable,Stream>,
    boost::is_base_and_derived<Seekable,Stream>
  >,
  some_type
>
some_function(const Stream& c);

SFINAE , Stream , .. , .

+6

:

STL ​​ . , , ( "" ) , . .

, , . ( ).

class shareable {...};
class seekable {...};

template <typename StreamType>
void needs_sharable_and_seekable(const StreamType& stream)
{
    BOOST_STATIC_ASSERT(boost::is_base_and_derived<shareable, StreamType>::value);
    BOOST_STATIC_ASSERT(boost::is_base_and_derived<seekable, StreamType>::value);
    ....
}

: , , "" :

#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/mpl/assert.hpp>

class shareable {};
class seekable {};

class both : public shareable, public seekable
{
};


template <typename StreamType>
void dosomething(const StreamType& dummy)
{
  BOOST_MPL_ASSERT_MSG((boost::is_base_and_derived<shareable, StreamType>::value),
                       dosomething_requires_shareable_stream, 
                       (StreamType));
  BOOST_MPL_ASSERT_MSG((boost::is_base_and_derived<seekable, StreamType>::value),
                       dosomething_requires_seekable_stream, 
                       (StreamType));
}

int main()
{
  both b;
  shareable s1;
  seekable s2;
  dosomething(b);
  dosomething(s1);
  dosomething(s2);
}
+12

?

template <typename STREAM>
void doSomething(STREAM &stream)
{
  stream.share();
  stream.seek(...);
}
+1
0

, Seekable Shareable , , , (, assert ):

void foo(Stream *s) {
    assert(s != NULL);
    assert(dynamic_cast<Seekable*>(s) != NULL);
    assert(dynamic_cast<Shareable*>(s) != NULL);
}
0

"shareable" "seekable" "in" "out" "io". .

0

All Articles