Inline Functions and Performance in Class Design
A user-defined arithmetic type such as complex packages a mathematical value together with the operations that act on it inside one class.
Starting From the Class Listing
A user-defined arithmetic type such as complex packages a mathematical value together with the operations that act on it, all inside one class. Rather than starting from a definition, this article starts from the code itself. Read the class below once without worrying about every detail. Then, as you go through the sections, you will learn to locate each part by its job: storage, access, construction, arithmetic, and performance.
- re and im are the two double members that hold the state
- the constructors set those members; they are not shown being called in this snippet
real()andimag()are accessors that read the members- operator+= modifies the object in place and returns a reference to it
This listing is an illustrative reconstruction written to match the structure the source describes: two double members, a constructor that takes a single scalar, accessors for the real and imaginary parts, and a compound assignment operator. The source's own class is the reference point; the snippet is a teaching aid that follows the same pattern. Use it to practice finding each part of the class by its role.
Where the Data Lives
The complex class stores its state in two double members, named re and im. These sit before the public label, which means other code cannot reach them directly. Everything after the public label is the interface, the set of operations that outside code is allowed to use. This split between hidden data and public operations is the core of the design. The data is the representation: the internal structure that holds one complex value. The public functions are the only doorway to that data.
The entire stored state of one complex object is therefore two double fields and nothing else. Every constructor, getter, setter, and operator in the class works by reading or writing these two fields. A complex value is just a pair of doubles that the class agrees to interpret as a real part and an imaginary part. When you are unsure what a complex value is, return to that picture.
The source explains that the class definition contains only the operations that need direct access to the representation. Operations that can be written using the public interface, or that are less central, are placed elsewhere. This is why multiply-assign and divide-assign appear only as declarations: their bodies live outside the class. The accessors real and imag are members too, so they share the same access to the representation.
Tracing a Constructor and a Compound Assignment
Work through a small trace with the class above. Suppose the first line creates a complex object from one scalar, and the second line applies += with a second complex value. The first line's result is decided entirely by the one-scalar constructor. The second line's result is decided entirely by the body of += in the class. The body of += does not mention the constructor at all. It only reads the two members of its argument and adds them to the members of the object it was called on. That is why the operator can be understood without knowing how the temporary was built.
- the one-scalar constructor sets the starting state
complex(1, 2)builds a temporary whose re is 1 and im is 2- += adds 1 to re and 2 to im, changing a in place
What do you think happens?
After a is built from the scalar 3 and then a += complex(1, 2) runs, what are the stored re and im of a?
Reveal answer
re is 4 and im is 2
The constructor sets re to 3 and im to 0. The += body adds the argument's re (1) to re, giving 4, and adds the argument's im (2) to im, giving 2. Only the two members of a change.
Both members changed because the operator body touches both re and im. The object itself was modified; no new object was created to hold the sum. That in-place behavior is what the compound operator is for.
Why += Returns a Reference
Inside the body of operator+=, the names re and im refer to the members of the object on the left of the += sign. The parameter z is the value on the right. Because the function is a member, it has direct access to the representation, which is exactly what it needs to add two complex values part by part.
The return type of += and -= is complex&, a reference to the object itself. The body ends by returning the dereferenced this pointer, so the function hands back the very object it modified. Returning a reference rather than a copy is what allows the result of one compound assignment to be used directly in another expression, while the original object is still changed in place.
- a +=
complex(1, 2)returns a reference to a, not a new object - the reference lets .imag() be called on the updated a directly
- a is changed; no copy of the result was made
What Inlining Changes and What It Does Not
The source explains that a complex type has to be efficient, or programmers will not use it. Arithmetic on a number type is performed constantly, so the overhead of each operation matters. For this reason, simple operations such as constructors, +=, and imag() are expected to be implemented without function calls in the generated machine code. This is what inlining means: the body of the function is placed where it is used instead of being reached through a call.
Two facts about inlining apply to this class. First, functions defined inside a class are inlined by default, so the short bodies in the class listing benefit without extra work. Second, the keyword inline can be written before a function declaration to require inlining explicitly. Either way, inlining is a performance decision. The class returns the same values whether or not a particular function is inlined.
The source also notes that a full industrial-strength complex, such as the one in the standard library, is carefully implemented to do appropriate inlining. The class you have been reading is a small teaching version, and its performance properties follow from the same idea on a smaller scale.
Mistakes When Reading Arithmetic Classes
Common mistake Assuming += creates a new complex object for the sum
What it looks likecomplex a(3); a += complex(1, 2);Why it failsThe body of operator+= modifies the members of the object it was called on and returns a reference to it.
Do this insteadRead a += b as changing a in place, so a itself holds the new re and im afterward.
Common mistake Looking for the += logic inside the constructor
What it looks likeTracing how complex(1, 2) was built to explain the sum
Why it failsThe += body only reads the two members of its argument, so it does not depend on how the temporary was constructed.
Do this insteadTrace the constructor for the starting state and the operator body for the change, separately.
Common mistake Treating the data members as public because they are declared in the class
What it looks likeWriting a.re directly from code outside the class
Why it failsThe members re and im sit before the public label, so outside code reaches them only through the public interface.
Do this insteadUse real(), imag(), or the declared operators to read or change the value.
Common mistake Believing an inlined function can return a different value
What it looks likeExpecting imag() to give a different answer once it is inlined
Why it failsInlining changes where the function body is placed in the generated code, not what the body computes.
Do this insteadCompare results by inputs and the function's definition; inlining is a performance property.
Common mistake If an arithmetic expression fails to compile, the operator used may not be declared in the class; check the public interface first
Practice Tracing a Complex Object
Using the class above, trace this sequence: complex a(5); then a += complex(2, -1); then a += complex(0, 4). What are the final re and im of a, and which members changed on each += call?
Hints
- The constructor
complex(5)sets re to 5 and im to 0. - Each += adds the argument's re to re and the argument's im to im.
- Track re and im separately across both += calls.
Explain, in two or three sentences, why a += b returning complex& lets the code write (a += b).imag() without making a copy, and say which object imag() reads.
Hints
- Think about what the function returns: a reference to the object it modified.
- Ask which object is updated when the sum is computed.
Key Takeaways
- A user-defined arithmetic class such as complex keeps its state in hidden double members, re and im, and exposes them only through its public interface.
- Compound operators such as += modify the object in place, and they return a reference to that object so that the result can be used directly in another expression.
- Each part of the class has a job: data members store the value, accessors and operators form the interface, and the operator bodies perform the arithmetic.
- Simple operations such as constructors, +=, and
imag()are expected to be inlined for performance; functions defined inside a class are inlined by default, and the inline keyword can require it explicitly. - Inlining changes how the generated code reaches a function body, not the value the class returns to the caller.