2

I've in the past used base classes purely for making type information constant (similar to traits classes, as well as perhaps ios_base). These classes would typically have no data, but only provide types that are commonly used (perhaps decorating an original type), the idea being in the event of change, changing the type constant at one location. I've been wondering if there are any advantages in using virtual inheritance for interfaces that might inherit from such type classes. A well known example of a similar case is interfaces that may derive boost::noncopyable (not that I often use boost::noncopyable for interfaces).

Here follows a little example of the case in question:

#include <iostream>
#include <memory>


struct Path{};

struct SomeTypeDefs //Or something providing services similar boost::noncopyable
{
    typedef std::shared_ptr<Path> PathPtr;
};


struct InterfaceX : SomeTypeDefs
{
    virtual PathPtr getPathX() const = 0;
};

struct InterfaceY : SomeTypeDefs
{
    virtual PathPtr getPathY() const = 0;
};

struct Impl : InterfaceX, InterfaceY
{
    private:
      PathPtr getPathY() const override{ return PathPtr{}; }
      PathPtr getPathX() const override{ return PathPtr{}; }
};

void foo(const InterfaceX&)
{
    std::cout << "foo X" << std::endl;
}
void foo(const InterfaceY&)
{
    std::cout << "foo Y" << std::endl;
}

int main() 
{
    Impl impl;
    foo(static_cast<InterfaceX&>(impl));
    foo(static_cast<InterfaceY&>(impl));
    return 0;
}

I can't see the benefit of using virtual inheritance in this case (is there any)?

Werner Erasmus
  • 3,988
  • 17
  • 31

1 Answers1

1

WARNING: Opinion, probably doesn't answer the question directly..

Frankly this type of situation is better handled by a policy class rather than inheritance!

For example, I would have

struct SomeTraits {
  typedef std::shared_ptr<Path> PathPtr;
};

// here class is hard-wired to policy
struct InterfaceX
{
    virtual SomeTraits::PathPtr getPathX() const = 0;
};

struct InterfaceY
{
    virtual SomeTraits::PathPtr getPathY() const = 0;
};

Then you can do this:

// here class doesn't really care about specific policy...
template <typename Traits>
struct InterfaceX
{
    typedef typename Traits:: PathPtr;
    virtual PathPtr getPathX() const = 0;
};

template <typename Traits>
struct InterfaceY
{
    typedef typename Traits:: PathPtr;
    virtual Traits getPathY() const = 0;
};

Which gives you lot's of possibilities (see policy based design..) I think it's frankly a lot cleaner than inheritance, specifically if you are defining types!

Nim
  • 33,299
  • 2
  • 62
  • 101
  • So would it then be considered bad practice to pull a lot of names (of types) into scope by means of public inheritance, similar to what is done when deriving from ios_base (apart from the fact that it has a little bit of state as well)? This way one would not need to qualify each name in a particular context where one wants all those names unqualified. OTOH perhaps an interface should not be as fat as ios_base (typedefing many types iaw the trait...). To pull in one or two types this way is fine – Werner Erasmus Sep 26 '16 at 14:22
  • Frankly speaking, if you are just pulling in types, then it's pointless abusing inheritance for it; I guess `ios_base` defines more than types.. The nice thing with collecting the types in such traits classes and then adopting the policy based design is that it becomes relatively easy to switch the "policies", in your model, if you wanted to have let's say for argument's sake `PathPtr` as `unique_ptr`, you can't have two side-by-side, it's only one model.. may be it works for you, but then I'd still avoid inheritance and simply have a `using` at the top to avoid having the fqn.. – Nim Sep 26 '16 at 14:37