Struct versus Class Default Access When Exposing Types Across a Library Boundary
0 reputation · 19 Dec 2023, 23:56 UTC
0 reputation · 19 Dec 2023, 23:56 UTC
The goal is to determine whether a library's public header should use struct or class when declaring a type that callers are expected to treat as opaque, given that the default member and base‑class access differ between the two keywords.
When a struct is chosen for brevity, its members and base classes become public by default, which can unintentionally expose implementation details and affect ABI compatibility if the type is later extended with non-public data or functions. The uncertainty lies in predicting how future changes to the type will impact existing binaries and whether callers might inadvertently depend on those now-public members.
What are the risks of relying on struct's default public access for a type intended to be opaque? How should library designers decide between struct and class to preserve encapsulation and ABI stability?
Use class (or an explicit private: section in a struct) for opaque types in public headers. struct defaults to public member and base-class access, which lets callers legally depend on implementation details. class defaults to private, preventing accidental exposure and preserving the library's freedom to change internals without breaking the ABI—provided the type's definition remains hidden and only forward-declared in the header.
struct members and bases are public by default; class members and bases are private by default.struct for Opaque Typesprivate:. If the library later adds a helper field or changes a base, existing binaries that happened to use that member will break or exhibit undefined behavior.private: instantly expands the public surface.class Foo; or struct Foo;—keyword irrelevant. Stop here.sizeof in client code.) If yes, use class and explicitly mark any public interface with public:. If no, forward-declare and define in the .cpp file.struct for style: Immediately add private: before any data members. Treat it identically to class.class (or struct + private:) the compile fails; with plain struct it succeeds.abi-compliance-checker or similar on two library versions where a private data member is added. Confirm no ABI break when the type is properly encapsulated.Does the opaque type need to be a complete type in the header (e.g., returned by value, stored directly in client containers, or used as a template argument)? If yes, the full definition must be visible and class with explicit public: for the intended interface is the safe default. If no, forward-declare and avoid the question entirely.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.