Werner Erasmus Werner Erasmus - 2 months ago 11
C++ Question

type providing bases classes (or noncopyable) and virtual inheritance

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)?

Nim Nim
Answer

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!

Comments