Access Modifiers in Java and C++

Difficulty: Beginner

Question

Explain the access modifiers in Java. How do they differ from C++, and which is the default?

Answer

Access modifiers are the keywords that decide who is allowed to see and use a class member. They are the practical tool behind encapsulation: without them, hiding data would be a polite suggestion instead of an enforced rule. Let me walk from the most restrictive to the most open.

Private means the member is visible only inside the class that declares it. Not even subclasses can touch it directly. This is your default choice for fields. Package-private, also called default, is what you get when you write no modifier at all. The member is visible to any class in the same package but not outside it, not even to subclasses in another package. This surprises many students because there is no keyword named default for this purpose. Protected means visible within the same package plus subclasses in any package, but for a subclass in a different package the access works only through inheritance (via a reference of the subclass type), not through a plain parent reference. Public means visible everywhere.

A neat way to remember: private is class only, default is package, protected is package plus children, public is world. For top-level classes only two options are allowed: public or package-private. A public class must live in a file with the same name. Local variables cannot have access modifiers at all.

A few extra rules. Constructors follow the same modifiers, which is how private constructors block instantiation. When overriding, you cannot reduce visibility, so a public method in the parent cannot be overridden as protected. Also, interface methods are implicitly public, and interface fields are implicitly public static final.

Now the C++ comparison. C++ has private, protected, and public, but no package-private, since it has no packages in the Java sense (namespaces do not restrict access). The default depends on the keyword used to declare the type: members of a class are private by default, and members of a struct are public by default. C++ also lets you control inheritance visibility: class D : private Base makes all inherited public members private in D. Java has no such thing; inheritance is always effectively public. C++ has friend classes and functions that can bypass private access, which Java has no direct equivalent for. Python has no enforced modifiers; a single underscore is a convention for protected, and double underscore triggers name mangling for pseudo-private.

Choose modifiers by the principle of least privilege: make everything as private as possible, then relax only when needed. That keeps your public surface area small, which keeps the class easy to change later without breaking users.

In the example below, Derived can read b, c, and d but not a. Trying to read a would be a compile error, which is precisely the protection the modifier provides.

Code examples

What a subclass can see

class Base {
    private int a = 1;
    int b = 2;              // package-private
    protected int c = 3;
    public int d = 4;
}

class Derived extends Base {
    int sum() {
        // return a + b + c + d;  // compile error: a has private access
        return b + c + d;
    }
}

public class AccessDemo {
    public static void main(String[] args) {
        System.out.println(new Derived().sum());
    }
}

Base and Derived share a package here, so package-private b is accessible. In a different package, b would not be.

C++ defaults: class vs struct

#include <iostream>
using namespace std;

struct S { int x = 1; };                       // public by default
class  C { int y = 2; public: int gety() { return y; } };  // private by default

int main() {
    S s; C c;
    cout << s.x << c.gety() << endl;
}

Key points

Concepts covered

access-modifiers, private, protected, package-private