0

I am developing quite a large Class whose objects require relatively costly validation if they are created by the public constructors, but for which the validation can be dispensed with for private constructors (since one can assume to be working with already-validated data).

In C++, is it possible to overload an operator (e.g. add or +) with the same signature in such a way that a different version of it is called from 'outside' the class (with input validation) and a different version is called from a member function (without the validation)?

For example, I'd like something like this:

class cBigClass { ... public: friend cBigClass operator*(const int a, const cBigClass& C) { this->Validate(a); cBigClass B = this->ComplicatedFunctionActuallyImplementingMultiply(a, C); return B; } private: friend cBigClass operator*(const int a, const cBigClass& C) { cBigClass B = this->ComplicatedFunctionActuallyImplementingMultiply(a, C); return B; } private: void DoSomethingPrivately() { int a = 1; cBigClass C, D; D = a*C; // Calls 'private' version of * without validation } }; ... // Elsewhere, e.g. in main() int a = 2; cBigClass A, B; A = a*B; // Calls 'public' version of * with validation 

A naive re-definition obviously throws a compiler error (g++), even when one is made public and one private. Both versions of such a function essentially have to have the same signature - is there a trick / hack for something like this? I would really like to avoid re-defining the operator code since it would lead to a lot of duplication.

8
  • 2
    Write everything without validation, then wrap that class with validation for public use. Commented Oct 11, 2024 at 8:54
  • "In C++, is it possible to overload an operator (e.g. add or +) with the same signature in such a way that a different version of it is called from 'outside' the class (with input validation) and a different version is called from a member function (without the validation)?..." No. D = a*C; and A = a*B; are doing the same thing/operation. So distinguishing between the two based on where they occur is just not possible. Commented Oct 11, 2024 at 8:56
  • "a different version is called from a member function (without the validation)" -- How do you know that the member function is called on an object that does not need validation (that was constructed by one of the private constructors, according to your logic)? Commented Oct 11, 2024 at 9:24
  • Short answer: no. For any given expression, the logic for resolution of an expression to function calls (e.g. a = b * C becomes something like a.operator=(b.operator*(C))) is the same, regardless of where the expression occurs. Access control (e.g. to prevent calling a private function by a non-member/non-friend) occurs after that. The usual approach would be to provide private functions that can be called directly by a class's member functions (or friends) and provide a set of public functions which (optionally) do validation and call the private functions. Commented Oct 11, 2024 at 10:53
  • Wrapping validated data in its own class is another alternative, So you then have (private) friend cBigClass operator*(ValidatedInt, const cBigClass&). (Similar to gsl::not_null). Commented Oct 11, 2024 at 13:51

1 Answer 1

0

Most problems can be solved with another level of indirection/abstraction.

You can define a base class which defines the core features as protected. Then you can make your class to derived from that base class and redefine those functions with your validation steps.

An example is better than 1000 words:

class Base { protected: double multiply(double a, double b) // Only accessible for derived classes { return a*b; } }; class MyClass : public Base { private: void validate() { // Do whatever validation you want } public: double multiply(double a, double b) // User exposed function with validation included { validate(); return Base::multiply(a, b); } }; 

Live demo

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for this suggestion. I was hoping to have to avoid a wrapper Class since it would be quite a lot of refactorisation.
I assume you meant to make double multiply a virtual method instead of just hiding the base method. The hidden base method will remain accessible when you cast a MyClass instance to its base type.
@Thibe It was not necessary for the sake of the example, but anyway, it's a protected member function so it won't be accessible from the outside world anyway (so the cast to the base type won't expose it)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.