Functions and Classes¶
Functions define contracts; classes combine representation, invariants, and operations. Good interfaces make ownership and failure visible.
Parameter passing¶
| Form | Typical meaning |
|---|---|
T value |
Copy/move a small value or take ownership of the argument value |
T const& value |
Read an existing object without copying; must not outlive it |
T& value |
Mutate a caller-owned object |
T* value |
Optional or reseatable non-owning access when null has meaning |
std::unique_ptr<T> |
Transfer exclusive ownership |
std::shared_ptr<T> |
Share ownership as part of the contract |
Do not use shared_ptr merely to avoid deciding ownership. Passing a smart
pointer is appropriate when its ownership semantics are relevant to the callee.
A class invariant¶
class percentage {
public:
explicit percentage(double value) : value_{value} {
if (!(value >= 0.0 && value <= 100.0)) {
throw std::out_of_range{"percentage outside [0, 100]"};
}
}
[[nodiscard]] double value() const noexcept { return value_; }
private:
double value_;
};
The constructor establishes the invariant and no operation can violate it.
explicit prevents unintended conversion from double. [[nodiscard]]
requests a diagnostic when a result is ignored; noexcept is part of the
function type and optimization/failure contract.
Construction and destruction¶
Members initialize in declaration order, not initializer-list order. Base subobjects initialize before members; destruction occurs in reverse order. Avoid calling virtual functions from constructors/destructors expecting dispatch to a more-derived override: the more-derived part is not active in that way.
Rule of Zero¶
Prefer members that manage their own resources—values, containers, strings, and smart pointers—so the compiler-generated destructor, copy/move constructors, and assignments have correct semantics. If a class manually manages a resource, the Rule of Five highlights the special operations that require review.
Overloading and default arguments¶
Overload resolution is compile-time. Default arguments are also substituted according to the declaration visible at the call site; they are not dynamically dispatched. Avoid overload sets whose conversions make calls ambiguous or surprising.
Headers and definitions¶
Headers normally contain declarations, class definitions, templates, and
appropriately inline definitions. Source files contain non-inline definitions.
Use include guards or #pragma once according to project policy, minimize
unnecessary includes, and avoid placing broad using namespace directives in
headers.
Exercises¶
- Design a class whose constructor establishes a non-empty name invariant.
- Explain why member initialization order follows declaration order.
- Decide how a function should accept a large read-only object that it does not retain.