Skip to content

Access Control and Friendship

C++ provides fine-grained access control through public``protectedAnd private specifiers, Plus the friend mechanism for granting selective access to non-members. Access control is enforced Entirely at compile time with zero runtime cost.

A class member can be declared with one of three access specifiers [N4950 S14.3.1]:

SpecifierClass membersDerived class membersExternal code
publicYesYesYes
protectedYesYesNo
privateYesNoNo

Access control is enforced at compile time only; it has zero runtime cost. The access specifier Applies to all members declared after it until another access specifier is encountered.

Formal definition. A member of a class is accessible from a particular point in the program if And only if the access rules in [N4950 S14.3] permit it. The three access specifiers define the Following accessibility sets:

  • public: the member is a member of the access interface of the class and is accessible from anywhere the class itself is accessible [N4950 S14.3.1.1].
  • protected: the member is accessible from member functions and friends of the class, and from member functions and friends of derived classes [N4950 S14.3.1.2].
  • private: the member is accessible only from member functions and friends of the class that declares it [N4950 S14.3.1.3].
#include <cstdio>
class Account {
private:
double balance_ = 0.0;
void log(const char* msg) const {
std::printf("[LOG] %s: balance=%.2f\n", msg, balance_);
}
protected:
void set_balance(double b) { balance_ = b; }
public:
void deposit(double amount) {
balance_ += amount;
log("deposit");
}
double balance() const { return balance_; }
};
class SavingsAccount : public Account {
public:
void apply_interest(double rate) {
set_balance(balance() * (1.0 + rate)); // protected: accessible
}
};
int main() {
Account a;
a.deposit(100.0);
// a.set_balance(50.0); // error: protected
// a.balance_ = 0; // error: private
// a.log("test"); // error: private
SavingsAccount s;
s.deposit(200.0);
s.apply_interest(0.05);
}

Proof: Access Control is Compile-Time Only

Section titled “Proof: Access Control is Compile-Time Only”

The access rules in [N4950 S14.3] apply during name lookup and access checking, which are phases Of translation (compilation). The generated object code contains no guards, checks, or indirections Related to access control. Therefore, the cost is provably zero at runtime: the access specifier Does not affect the object layout, function calling convention, or any aspect of the execution Model.

In C++, class and struct are identical except for one default: in a classMembers are private by default; in a structMembers are public by default [N4950 S13.3].

struct S { int x; }; // x is public
class C { int x; }; // x is private
static_assert(sizeof(S) == sizeof(C));