6
$\begingroup$

C++ and Objective-C both require forward declaration of the methods and fields on a class. Objective-C lets you hide the existence of internal/private methods & fields altogether:

// MyObject.h
#ifndef _MyObject_h_
#define _MyObject_h_

#import <Foundation/Foundation.h>

@interface MyObject : NSObject {
  NSInteger publicIvar;
}

- (void)publicMethod;

@end

#endif

// MyObject+Internal.h
#ifndef _MyObject_Internal_h_
#define _MyObject_Internal_h_

#import "MyObject.h"

@interface MyObject () {
  NSInteger internalIvar;
}

- (void)internalMethod;

@end

#endif

// MyObject.m
#import "MyObject+Internal.h"

@implementation MyObject {
  NSInteger privateIvar;
}

/* method implementations */

@end

If the project is configured such that dependents can’t import MyObject+Internal.h, they can’t use the symbols from that extension. However, C++ doesn’t allow this; all fields and methods must be declared in one place. Dependents are able to see things that they can’t use.

In a language like these that requires forward declarations, what are the advantages of requiring private functionality to be declared in a public header?

$\endgroup$

2 Answers 2

9
$\begingroup$

As also explained by the other answer, all member variables need to be declared in the header, because by themself all types in C++ are value types. This implies that the compiler needs to know their size and alignment to allocate them on the stack, and that is computed from the member variables.

Private methods however wouldn't necessarily need to be declared in the header. This is a somewhat unfortunate state of affairs, especially if your private methods take argument types that you don't want to expose in the header.

If you really wanted, you could in your .cpp file #define private public and just define private member functions as static free functions that take the object by reference or pointer. Note that this suggestion is not really serious, because it violates the one definition rule. Also the compiler is allowed to reorder private member variables, which would totally break your builds, but no compiler does this in practice.

In practice you need to work around these issues, and if all else fails there is always the ultimate code insulation tool that is the pimpl-idiom.

And there certainly are situations where the declarations are necessary. E.g. if you have a really big class where you have multiple .cpp files for the implementation, you need them if it is used in another files that where it is defined. Or public inline functions that reference the private functions. Or friend functions and classes that may need access to them.

So I assume that in the end there so many situations where you need the declarations, that the gained insulation is just not worth the effort and the added fragmantation and complexity that would come with retroactively fitting a solution into the language at this point.

$\endgroup$
1
  • $\begingroup$ That’s a good point about stack allocation — all objects in Objective-C are pointers to heap memory. $\endgroup$
    – Bbrk24
    May 25, 2023 at 18:16
5
$\begingroup$

The private attributes may effect the position of public attributes. If you have a class like this:

class A {
   public:
       int a;
}

Here, a is placed at the first position, thus x.a translates to *(a+0). But on the other hand if you have this:

class A {
    private:
        int b;
    public:
        int a;
}

Here, a is will be stored at *(x+1), a different place. The private variable, while not directly accessible, effects accesses to public variables.

I can speak from experience that absolutely everything breaks when your variables are not where you expect them to be, from when I tried to #ifdef out private methods when a header was included.

I'm guessing it works the same way for methods for consistency.

$\endgroup$
1
  • $\begingroup$ Doesn't directly answer the whole question, but it could probably bear extending with "and if that's how it is for fields, then it's extra effort for less utility to make it work with methods anyways". $\endgroup$ May 25, 2023 at 17:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .