C++ typedef inheritance ambiguous problem

627 views Asked by At

I wish to use a helper class which would only make few Qt typedef aliases for the given template argument. Ofc ambiguous comes a cross very quickly and also quite often with my current design situation on the project, since one wish to access Base as well as Derived. Not sure if this problem is somehow workaround-able, still giving it a shot. Example:

template <class T> class SmartAlias
{
public:
    typedef QSharedPointer<T> Shared;
};

class Base : public SmartAlias<Base>
{
};

class Derived : public Base, public SmartAlias<Derived>
{
};

Base::Shared base;  // Normally works
Derived::Shared derived;  // ambiguous problem

Any ideas of a better solution? Thanks.

SUMMARY/UPDATE/SOLUTION

To sum it up, if one wishes to use this, go with Anton Savin idea, which can also be extended for multiple inheritance using virtual inheritance:

#include <vector>

template <typename T, typename... MyBases> class SmartAlias :  virtual public MyBases... {
public:
    typedef std::vector<T> Shared;
};

class Base : public SmartAlias<Base>
{
};

class Derived : public SmartAlias<Derived, Base>
{
};

class MiniBase : public SmartAlias<MiniBase> {};

class MiniDerived : public SmartAlias<MiniDerived, MiniBase, Derived> { 
public: 
    MiniDerived() : MiniBase(), Derived() 
    {
    }
};

int main() {
    Base::Shared base;
    Derived::Shared derived; 
    MiniDerived::Shared md;
}

I on the other hand will stick with my current solution that Frerich Raabe mentioned.

3

There are 3 answers

6
Anton Savin On BEST ANSWER

You can explicitly specify in Derived which of two Shareds you want to use:

class Derived : public Base, public SmartAlias<Derived>
{
public:
    using Shared = SmartAlias<Derived>::Shared;
    // or in pre-C++11
    typedef SmartAlias<Derived>::Shared Shared;
};

Here is another option which doesn't require to add typedefs to all classes. Instead it modifies the hierarchy inserting SmartAlias between Base and Derived:

template <typename T, typename MyBase = void> class SmartAlias : public MyBase
{
public:
    typedef typename SmartAlias<T>::Shared Shared;
};

template <typename T> class SmartAlias<T, void> 
{
public:
    typedef QSharedPointer<T> Shared;
};

class Base : public SmartAlias<Base>
{
};

class Derived : public SmartAlias<Derived, Base>
{
};
3
Venkatesh On

The problem is when you create a Derived object it will intern create an object for Base that will intern create an object for SmartAlias and then you intensionally deriving SmartAlias from Derived. So you are having 2 SmartAlias objects for a single Derived object. When you want access a member of SmartAlias using Derived object surely it will lead to ambiguous. So you need not have SmartAlias as the immediate base for Derived.

1
Frerich Raabe On

Quite frankly, seeing code which uses (public) inheritance for code reuse instead of interface reuse always makes me nervous. And a class which has 'Smart' in its name is almost a code smell to me. How about just

class Base
{
public:
    typedef QSharedPointer<Base> Shared;
};

class Derived : public Base
{
public:
    typedef QSharedPointer<Derived> Shared;
};