23

The answer to why we put private member variables in C++ headers is that the size of the class must be known at points where instances are declared so that the compiler can generate code that appropriately moves about the stack.

Why do we need to put private members in headers?

But is there any reason to declare private functions in the class definition?

The alternative would be essentially the pimpl idiom but without the superfluous indirection.

Is this language feature more than a historical error?

7 Answers 7

14

Private member functions may be virtual, and in common implementations of C++ (that use a vtable) the specific order and number of virtual functions is required to be known by all clients of the class. This applies even if one or more of the virtual member functions is private.

It might seem that this is like "putting the cart before the horse", because compiler implementation choices shouldn't affect the language specification. However, in reality the C++ language itself was developed at the same time as a working implementation (Cfront), which used vtables.

5
  • 5
    "implementation choices shouldn't affect the language" is almost the exact opposite of the C++ mantra. The specification doesn't mandate any particular implementation, but there are a lot of rules specifically crafted to serve the requirements of a particularly efficient implementation choice.
    – Ben Voigt
    May 16, 2014 at 1:06
  • This sounds very plausible. Is there a source on this? May 16, 2014 at 2:47
  • @Praxeolitic: You can read about the Virtual method table. May 16, 2014 at 2:55
  • 1
    @Praxeolitic - find an old copy of the 'The Annotated C++ Refernce Manual' (stroustrup.com/arm.html) - the authors talk about various implementation details and how it shaped the language. May 16, 2014 at 19:37
  • 2
    I'm not sure this really answers the question. To me it just addresses one specific facet - albeit well - and leaves behind the rest: Why do we need to put non-virtual private member functions in headers? Sure, purely for consistency/simplicity is one argument - but ideally we'd have a mechanistic and/or philosophical rationale too. So, I've added an answer that I believe explains this as a very deliberate design choice with very beneficial effects. Jul 10, 2016 at 8:24
15

If you allowed methods to be added to a class outside its definition, they could be added anywhere, in any file, by anyone.

That would immediately give all client code trivial access to private and protected data members.

Once you've finished the class definition, there's no way to mark some files as being specially blessed by the author to extend it - there are just flat translation units. So, the only reasonable way to tell the compiler that a particular set of methods are official, or blessed by the class author, is to declare them inside the class.


Note that we have direct access to memory in C++, which means it's generally trivial to create a shadow type with the same memory layout as your class, add my own methods (or just make all the data public), and reinterpret_cast. Or I can find the code of your private function, or disassemble it. Or lookup the function address in the symbol table and call or directly.

These access specifiers don't try to prevent these attacks, because that isn't possible. They only indicate how a class is supposed to be used.

9
  • 1
    The class definition could refer to a function container entity hidden from client code. Alternatively, this could be inverted and a complete traditional class definition hidden from client code could designate a visible interface that only describes public members and can reveal its size. May 15, 2014 at 17:03
  • 1
    Sure, but the compilation model doesn't provide a reasonable way to stop client code interposing its own version of the hidden container or a different visible interface with extra accessors.
    – Useless
    May 15, 2014 at 17:19
  • That's a good point, but isn't this true for the definitions of all member functions not in the header anyway? May 15, 2014 at 17:27
  • 1
    All member functions are declared inside the class though. The point is that you can't add new member functions that weren't at least declared in the class definition (and the one definition rule prevents multiple definitions).
    – Useless
    May 15, 2014 at 17:30
  • Then what about a one container of private functions rule? May 15, 2014 at 17:41
15

The accepted answer explains this for virtual private functions, but that only answers one specific facet of the question, which is considerably more limited than what the OP asked. So, we need to rephrase: Why are we required to declare non-virtual private functions in headers?

Another answer invokes the fact that classes must be declared in one block - after which they're sealed and cannot be added to. That's what you'd be doing by omitting to declare a private method in the header then trying to define it elsewhere. Nice point. Why should some users of the class be able to augment it in a way that other users can't observe? Private methods are part of it and aren't excluded from this. But then you ask why they're included, and it seems a bit tautological. Why must class users know about them? If they weren't visible, users couldn't add any, and hey presto.

So, I wanted to provide an answer that, rather than just including private methods by default, provides specific points in favour of having them visible to users. A mechanistic reason for non-virtual private functions requiring public declaration is given in Herb Sutter's GotW #100 about the Pimpl idiom as part of its rationale. I won't go on about Pimpl here, as I'm sure we all know about it. But here's the relevant bit:

In C++, when anything in a header file class definition changes, all users of that class must be recompiled – even if the only change was to the private class members that the users of the class cannot even access. This is because C++’s build model is based on textual inclusion, and because C++ assumes that callers know two main things about a class that can be affected by private members:

  • Size and Layout: [of members and virtual functions - self-explanatory and great for performance, but not why we're here]
  • Functions: The calling code must be able to resolve calls to member functions of the class, including inaccessible private functions that overload with nonprivate functions — if the private function is a better match, the calling code will fail to compile. (C++ took the deliberate design decision to perform overload resolution before accessibility checking for safety reasons. For example, it was felt that changing the accessibility of a function from private to public shouldn’t change the meaning of legal calling code.)

Sutter is, of course, an extremely reliable source as a member of the Committee, so he knows "a deliberate design decision" when he sees one. And the idea of requiring public declaration of private methods as a way to avoid altered semantics or accidentally broken accessibility later is probably the most convincing rationale. Thankfully, as the whole thing seemed rather pointless before now!

3
  • "But then you ask why, and that answer seems tautological. Again, why do users of the class need to know about them?" No, it's not tautological. Users don't necessarily "need to know about them". What needs to happen is that you have to be able to prevent people from extending classes without the class writer's consent. So all such members must be declared up-front. That this causes users to know about private members is merely a necessary consequence. Jul 11, 2016 at 1:03
  • 2
    @NicolBolas For sure. That probably wasn't very good wording on my part. I meant that the answer only explains visibility of private methods as a consequence of a (very valid) rule that covers many things, rather than providing a rationale about visibility of private methods specifically. Of course, the real answer is a combination of Useless's, gnasher's, and mine. I just want to provide another perspective that wasn't here yet. Jul 11, 2016 at 10:10
  • 1
    This answer gave me the piece of mind that only a full insight into the depths of a matter can provide!!! This should be the accepted answer!!! The other answers are half-truths and opinions.
    – FooF
    Feb 18, 2020 at 5:11
4

There are two reasons for doing this.

First, realize that the access specifier is for the compiler, and is not relevant at runtime. Accessing a private member outside of scope is a compile error.

Conciseness

Consider a function that is short, one or two lines. It exists to reduce the replication of code elsewhere, which also has the advantage of being able to change how an algorithm or whatever else works in one place instead of many (e.g. changing a sorting algorithm).

Would you rather have a quick one or two line in the header, or have the function prototype there plus an implementation somewhere? It is easier to find in the header, and for short functions, it is far more verbose to have a separate implementation.

There is another major advantage, which is...

Inline Functions

A private function may be able to be inlined, and this necessarily requires it to be in the header. Consider this:

class A {
  private:
    inline void myPrivateFunction() {
      ...
    }

  public:
    inline void somePublicFunction() {
      myPrivateFunction();
      ...
    }
};

The private function may be able to be inlined along with the public function. That is done at the compiler's discretion, as the inline keyword is technically a suggestion, not a requirement.

5
  • All functions defined inside the class body are automatically marked inline, there's no reason to use the keyword there.
    – Ben Voigt
    May 16, 2014 at 1:04
  • @BenVoigt so it is. I did not realize that, and I have been using C++ part-time for quite a while. That language never ceases to surprise me with little nuggets like that one.
    – user22815
    May 16, 2014 at 14:06
  • I don't think a method needs to be in the header to be inlined. It just needs to be in the same compilation unit. Is there a case where it makes sense to have separate compilation units for a class? Mar 9, 2016 at 2:38
  • @SamuelDanielson correct, but a private function must be in the class definition. The very notion of "private" implies it is part of the class. It would be possible to have a nonmember function in the .cpp file that is inlined by member functions that are defined outside of the class definition, but such a function would not be private.
    – user22815
    Mar 9, 2016 at 6:38
  • The body of the question was "is there any reason to declare private functions in the class definition [sic, by which context shows OP really meant class declaration]". You're talking about defining the private functions. This doesn't answer the question. @SamuelDanielson Nowadays LTO means functions can be anywhere in a project and retain equal chance of being inlined. As for splitting a class to multiple translation units, the simplest case is that the class is just big and you want to semantically split it into multiple source files. I'm sure such large classes are discouraged, but anyway Jul 10, 2016 at 16:42
2

Another reason to have private methods in the header file: There are cases where a public inline method does not much more than calling one or several private methods. Having the private methods in the header means that a call to the public method can be completely inlined to the actual code of the private methods, and inlining doesn't stop with a call to the private method. Even from a different compilation unit (and public methods would usually be called from different compilation units).

Of course there's the reason as well that the compiler cannot detect problems with overload resolution if it doesn't know all methods, including private ones.

1
  • Excellent point about inlining! I imagine this is especially relevant for the stdlib and other libraries with methods defined inline. (if not so much for internal code, where LTO can do almost anything across TU boundaries) Jul 11, 2016 at 10:14
2

OTOH, private member functions aren't always necessary and none of the existing answers seem to speak to that.

I mean if you're just dealing with private member variables (and not things like needing access to private types), you can have your public member functions pass them as parameters to non-member, non-friend functions ("free functions" or even "pure functions") instead, and you can still be able to ensure that your class invariants are enforced. Then you can entirely do away with private member functions and having to have those declared in the header file with the class definition. As a side benefit, free/pure functions can be easier to unit test than private member functions. You can also define those functions within an anonymous namespace within a source file of your class's code and not need to have them declared in any header file at all. Similarly, one could also use lambda expressions with the same effect.

Of course the more private member variables a class uses, the more likely code will wind up passing an intolerable number of parameters this way (the C++ Core Guidelines I.23 suggests passing fewer than four). Then private member functions may look too convenient to pass up.

Arguably however, the more private member variables a class has, the more likely it's violating the single-responsibility principal. That suggests splitting apart the class into multiple smaller classes to reduce their individual number of responsibilities. This in turn would help avoid having to pass more parameters than desirable.

So while private member functions have to be declared in the class's definition per the language, neither the language nor encapsulation requires the use of private member functions to achieve the same end anyway.

1

It's to allow those functions to access the private members. Otherwise you'd need to friend them in the header anyway.

If any function could access the private members of the class then private would be useless.

1
  • 2
    Maybe I should have been more explicit in the question - I meant why is the language designed this way? Why must it be or why is this design a good one? May 15, 2014 at 17:04

Not the answer you're looking for? Browse other questions tagged or ask your own question.