Класс содержит инвариант. Инвариант устанавливается конструктором. Однако во многих ситуациях полезно иметь представление о состоянии представления объекта (которое вы можете передать по сети или сохранить в файл - DTO, если хотите). REST лучше всего делать с точки зрения AggregateType. Это особенно верно, если вы правы. Рассмотрим:
struct QuadraticEquationState {
const double a;
const double b;
const double c;
// named ctors so aggregate construction is available,
// which is the default usage pattern
// add your favourite ctors - throwing, try, cps
static QuadraticEquationState read(std::istream& is);
static std::optional<QuadraticEquationState> try_read(std::istream& is);
template<typename Then, typename Else>
static std::common_type<
decltype(std::declval<Then>()(std::declval<QuadraticEquationState>()),
decltype(std::declval<Else>()())>::type // this is just then(qes) or els(qes)
if_read(std::istream& is, Then then, Else els);
};
// this works with QuadraticEquation as well by default
std::ostream& operator<<(std::ostream& os, const QuadraticEquationState& qes);
// no operator>> as we're const correct.
// we _might_ (not necessarily want) operator>> for optional<qes>
std::istream& operator>>(std::istream& is, std::optional<QuadraticEquationState>);
struct QuadraticEquationCache {
mutable std::optional<double> determinant_cache;
mutable std::optional<double> x1_cache;
mutable std::optional<double> x2_cache;
mutable std::optional<double> sum_of_x12_cache;
};
class QuadraticEquation : public QuadraticEquationState, // private if base is non-const
private QuadraticEquationCache {
public:
QuadraticEquation(QuadraticEquationState); // in general, might throw
QuadraticEquation(const double a, const double b, const double c);
QuadraticEquation(const std::string& str);
QuadraticEquation(const ExpressionTree& str); // might throw
}
На этом этапе вы можете просто хранить коллекции кеша в контейнерах и искать их при создании. Удобно, если есть реальная обработка. Обратите внимание, что кэш является частью QE: операции, определенные в QE, могут означать, что кэш частично используется повторно (например, c не влияет на сумму); тем не менее, когда кеша нет, стоит поискать его.
Частное наследование может почти всегда моделироваться участником (при необходимости сохраняя ссылку на базу). Просто не всегда стоит так моделировать; иногда наследование является наиболее эффективным представлением.