3

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.

krizajb
  • 1,715
  • 3
  • 30
  • 43

3 Answers3

2

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>
{
};
Anton Savin
  • 40,838
  • 8
  • 54
  • 90
  • @krizajb in pre-C++11 you should use `typedef` instead – Anton Savin Nov 13 '14 at 09:53
  • Looks good. Forgot to describe a more detailed requirements making this solution cover only the basics. What if `Derived` extends `Base` but also extends another class which is also extended on same principle as `Derived` and `Base`. I get a compiler error, will analyze and get back to you. – krizajb Nov 13 '14 at 11:31
  • Example: class MiniBase : public SmartAlias { }; class MiniDerived : public SmartAlias, public SmartAlias { }; Everything works till I wish to call non default constructor of MiniBase or Derived in initialization list. Will look into it. – krizajb Nov 13 '14 at 11:44
  • Think I will have to use virtual inheritance for that one to work, which isn't the best solution out there :/ – krizajb Nov 13 '14 at 11:53
  • @krizajb Virtual inheritance won't help you. This will never work in case of multiple inheritance - you have to define `Shared` inside the class itself like in my first example. Or you can move multiple inheritance to SmartAlias itself – Anton Savin Nov 13 '14 at 11:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/64862/discussion-between-krizajb-and-anton-savin). – krizajb Nov 13 '14 at 11:59
2

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;
};
Anton Savin
  • 40,838
  • 8
  • 54
  • 90
Frerich Raabe
  • 90,689
  • 19
  • 115
  • 207
  • This is my current design. Was only thinking of making it easier and tried making a reusable code. As you probably know, there are plenty of other smart pointers :) – krizajb Nov 13 '14 at 09:58
0

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.

Venkatesh
  • 1,537
  • 15
  • 28