9

Let's say I have 2 classes that I want to be visible (within a given header file) and one class that is their ancestor, which one I want to be visible only to the previously mentioned two. How can I achieve such class functionality of being invisible in C++?

infoholic_anonymous
  • 929
  • 3
  • 12
  • 29
  • 12
    Why? Just make it abstract so it can't be instantiated but serves as an interface. This is _useful_. – Lightness Races in Orbit Dec 30 '12 at 17:10
  • 3
    You could namespace them, but I'm pretty sure you couldn't make them completely inaccesible – obmarg Dec 30 '12 at 17:10
  • I second what Lightness said, why would you want to? – StoryTeller - Unslander Monica Dec 30 '12 at 17:12
  • @LightnessRacesinOrbit maybe the functionality is templated. – Seth Carnegie Dec 30 '12 at 17:12
  • @Seth: And so therefore? – Lightness Races in Orbit Dec 30 '12 at 17:13
  • @LightnessRacesinOrbit and so therefore the templates can't be virtual and the class has to be in the header. – Seth Carnegie Dec 30 '12 at 17:13
  • @Seth: Okay so back to the original question why try to hide it? – Lightness Races in Orbit Dec 30 '12 at 17:14
  • @LightnessRacesinOrbit I don't know, that's his business. Hiding private base classes maybe? – Seth Carnegie Dec 30 '12 at 17:15
  • 3
    Rather than make the class an ancestor, you could make it a *contained* class, and use private implementation http://www.drdobbs.com/cpp/making-pimpl-easy/205918714 – Josh Greifer Dec 30 '12 at 17:15
  • @LightnessRacesinOrbit I'm still learning the OOP approach and it may indeed be a bad idea on my side, I've just thought it would be messy to declare simple classes globally that are of no use apart from inheritance. Haven't heard of abstract classes before, seems to be a suitable solution. – infoholic_anonymous Dec 30 '12 at 17:17
  • 6
    It's our business too if he is asking how to do it :) – Lightness Races in Orbit Dec 30 '12 at 17:18
  • The reason we ask why is because many times the problem is solved by going a different (better) direction altogether. – Bob Horn Dec 30 '12 at 17:41
  • @JoshGreifer: I shudder when I read said code, especially since template specializations need be in the same namespace as the specialized template; it's horrendous :x – Matthieu M. Dec 30 '12 at 18:24
  • 1
    @obmarg: That's what I'd have said too. It doesn't even matter that being namespaced does not _truly_ make the class inaccessible. If you have a class in something like `namespace implementation` or `namespace detail` and some prick feels compelled to use it anyway just because it's technically possible, that's his own problem. You've made the intent clear, that's what counts. If it crashes and burns after they've abused your clearly stated intent, and they come complaining, just tell them to f... off. – Damon Dec 30 '12 at 18:25
  • @LightnessRacesinOrbit Well as for now your solution seems the most suitable for me. You could turn it to answer I guess. – infoholic_anonymous Dec 30 '12 at 19:05
  • Also see [Hide class type in header](https://stackoverflow.com/q/3525552/608639), [How can I hide a class in C++?](https://stackoverflow.com/q/14092705/608639), [Hiding a C++ class in a header without using the unnamed namespace](https://stackoverflow.com/q/5780918/608639) – jww Sep 28 '17 at 23:22

4 Answers4

11

Abusing a class to act as a namespace will do this. I do not recommend this pattern.

class hidden_stuff {
private: // hide base from everyone
    struct base {
        // contents
    };
public:
    class derived1;
};
typedef class hidden_stuff::derived1 derived1;

class hidden_stuff::derived1
    : private hidden_stuff::base {}; // private inheritance required
            // or hidden_stuff::base is accessible as derived1::base

The real solution (though not technically satisfying the question)

A preferable solution would be to use a clearly-named namespace such as impl:: or detail::, which will convey to users that they shouldn't use any classes inside, and stop any possible undesired effects on overloading or the like. That's how most libraries (even Standard Library implementations) "hide" classes from the user.

Potatoswatter
  • 126,977
  • 21
  • 238
  • 404
  • 1
    I was kind of surprised to learn we could not use an unnamed namespace to hide classes in header files. It seems like the perfect tool (except its not allowed). – jww Sep 28 '17 at 23:18
  • I like the subdivision into a separate namespace – vincenzopalazzo Mar 09 '21 at 23:06
9

It is not possible.

C++ requires that a class be fully defined at the point it is used as a base, and because of its include mechanism anything that is fully defined at the point of definition of a class is necessarily visible to all who can see the definition of said class.

C++ has mechanisms to protect against Murphy (accidents) but not against Machiavelli (hacks).


That being said, the purpose is itself dubious, the only reason I can fathom would be to prevent the user from relying on the fact that your Derived class derives from this Fantom base. Well, deriving privately: class Derived: private Fantom {}; or using composition instead class Derived { private: Fantom _fantom; }; would both achieve this.

Matthieu M.
  • 251,718
  • 39
  • 369
  • 642
2

Instead of hiding class, I'd recommend diabling making use if it. In example:

class Hidden
{
  private:
    friend class Exposed;
    Hidden() {}
    int hidden_x;
};

class Exposed : private Hidden
{
  public:
    Exposed() : Hidden() {}
    void DoStuff() { printf( "%d" , hidden_x ); }
};

So what you can: - create any number of Exposed class instances in your code - call DoStuff() method from these instances

But you cannot: - instantiate Hidden class (private constructor) - operate on Hidden class members directly or via Exposed class (they are private)

Anonymous
  • 2,022
  • 14
  • 23
0

A variation of Anonymous answer, instead of private inheritance you can add private member of the hidden class.

class Hidden
{
   private:
      friend class Exposed;
      Hidden() {}
      int hidden_x;
};

class Exposed
{
  public:
      Exposed() {}
      void DoStuff() { printf( "%d" , hidden.hidden_x ); }
  private:
      Hidden hidden_;
};
Thesane
  • 1,128
  • 6
  • 16