karadoc
karadoc

Reputation: 2721

Public member without inheritance

I have a base class which looks something like this:

class Base
{
public:
  typedef std::shared_ptr<Base> ptr_t;
  typedef std::weak_ptr<Base> wptr_t;

  enum class Type { foo, bar, baz };

  Type x;
  // ...
};

I'd like those internal types to be public so that I can do stuff like Base::ptr_t my_ptr(new Base); and so on. But if I make a new class like this...

class Derived : public Base
{
  // ...
};

unfortunately, Derived::ptr_t is still a Base pointer. I'd like Derived to publicly inherit x from Base, but not inherit ptr_t,wptr_t, or Type. For example

Derived a;
a.x = Base::Type::foo; // this should work
a.x = Derived::Type::foo; // but I want this to fail

Is this possible, perhaps though some magic use of friend or virtual or something like that?

Upvotes: 3

Views: 177

Answers (3)

karadoc
karadoc

Reputation: 2721

Based on the answers of iammilind and Luc Danton, here's what I've come up with:

class Base
{
private:
  // only 'BaseClass' is allowed to derive from Base
  Base() { }
  friend class BaseClass;
public:
  typedef std::shared_ptr<Base> ptr_t;
  typedef std::weak_ptr<Base> wptr_t;

  enum class Type { foo, bar, baz };

  Type x;
  // ...
};

class BaseClass : public Base
{
private:
  // make all the raw_Base types private
  using Base::ptr_t;
  using Base::wptr_t;
  using Base::Type;
};

class Derived : public BaseClass
{
  // define as usual, and now all is well in the world.
};

// now, to test it
class Derived2 : public Base { }; // fails

Derived d;
d.x = Derived::Type::foo; // fails
d.x = Base::Type::foo; // works
// Which is exactly what I wanted.

As far as I can tell, the only problem with this solution is that it adds a new and potentially confusing class. The class is defined in such a way that it can't really be misused – Base itself cannot be derived from except by BaseClass, but still, BaseClass is an unattractive piece of namespace-clutter.

However, for the particular piece of code that I intend to use this in, I happen to be using the equivalent of BaseClass already to solve an unrelated problem. So this BaseClass technique suits my purposes just fine.

Upvotes: 0

iammilind
iammilind

Reputation: 70098

Simply override the type:

class Derived {
  typedef int Type;
};

It will not allow the use of Derived::Type (as it's private as well as typedefed)

Upvotes: 4

Luc Danton
Luc Danton

Reputation: 35469

class Derived : public Base
{
  // This is now private
  using Base::ptr_t;
  using Base::wptr_t;
  // ...
};

Upvotes: 3

Related Questions