Main Content

MISRA C++:2023 Rule 16.6.1

Symmetrical operators should only be implemented as non-member functions

Since R2024b

Description

Rule Definition

Symmetrical operators should only be implemented as non-member functions.

Rationale

The MISRA C++:2023 standard advises against defining these binary operators as class members.

ArithmeticRelationalBitwiseLogical

  • operator+

  • operator-

  • operator*

  • operator/

  • operator%

  • operator==

  • operator!=

  • operator<

  • operator<=

  • operator>

  • operrtor>=

  • operator^

  • operator&

  • operator|

  • operator&&

  • operator||

Consider the binary operator a op b that you define as a class member:

class myclass{
//...
myClass operator op (myClass rhs) const;
};
Because you define the operator as a class member, the class myClass can specify the type of only one out of the two operands. When you call the operator, the other operand might be converted to myClass implicitly or explicitly. This conversion can result in a compilation error or unexpected behavior. To avoid such inconsistent behavior, do not define binary operators as class members.

The best practice for implementing binary operators is to define them as a hidden friend function and then write the definition of the friend function with in the class. This way, the binary operator definition can specify the type of both operand. Unintended conversion during the operation can be prevented by using this technique. Compilers select such operators only when both operators match the required type, which reduces unexpected errors in the code.

Polyspace Implementation

Polyspace® reports a violation if you define any of the previously mentioned binary operators as class members.

The operators *, +, -, and & can be both binary and unary. Polyspace does not report a violation of this rule if you define the unary version of these operators as class members.

Troubleshooting

If you expect a rule violation but Polyspace does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

This example code defines two classes: myNoncompliantClass and myCompliantClass. In the class myNoncompliantClass, several binary operators are defined as class members. Implementing the binary operators as class members does not allow the class to specify the types for both operands. Only one operand is specified, and the other might be unexpectedly converted to myNoncompliantClass, resulting in unexpected behavior. Polyspace reports violations of this rule for the binary operators that are defined as class members.

The recommended best practice for binary operators is to define them as hidden friend functions. In the class myCompliantClass, the binary operators are specified as friend functions and their definition is kept with in the class. The binary operators defined this way explicitly specifies the type of both operands. As a result, this implementation of binary operators avoids unexpected conversions. Polyspace reports no violations of this rule.

class myNoncompliantClass {
public:
	myNoncompliantClass(int i): val(i) {}

	myNoncompliantClass operator+(myNoncompliantClass oth) {       //Noncompliant
		return myNoncompliantClass(oth.val + val);
	}



	myNoncompliantClass operator-(myNoncompliantClass oth);        //Noncompliant
	myNoncompliantClass operator*(myNoncompliantClass oth);        //Noncompliant
protected:
	myNoncompliantClass operator==(myNoncompliantClass oth);       //Noncompliant
private:
	myNoncompliantClass operator!=(myNoncompliantClass oth);       //Noncompliant

	int val;
};

class myCompliantClass {
public:
	myCompliantClass(int i): val(i) {}

	friend myCompliantClass operator+(myCompliantClass lhs, myCompliantClass rhs) {      //Compliant
		return myCompliantClass(lhs.val + rhs.val);
	}


	friend myCompliantClass operator*(myCompliantClass lhs, myCompliantClass rhs) {/*..*/} // Compliant
	friend myCompliantClass operator-(myCompliantClass lhs, myCompliantClass rhs) {/*..*/} // Compliant
protected:
	friend myCompliantClass operator==(myCompliantClass lhs, myCompliantClass rhs) {/*..*/} // Compliant
private:
	friend myCompliantClass operator!=(myCompliantClass lhs, myCompliantClass rhs) {/*..*/} // Compliant

	int val;
};

Check Information

Group: Overloading
Category: Advisory

Version History

Introduced in R2024b