To give a more direct idea of what you can expect, let's start with a simple class like this:
class Integer {
int a;
public:
Integer(int a) : a(a) {}
friend Integer operator+(Integer a, Integer b) {
return Integer(a.a + b.a);
}
friend std::ostream &operator<<(std::ostream &os, Integer const &i) {
return os << i.a;
}
};
For the sake of demonstration, let's add a main
that reads some data from the outside world, creates a couple of Integer objects, and then prints out the result of adding them. The inputs and outputs will come from the outside world, so the compiler can't pull too fancy of tricks, and optimize everything out.
int main(int argc, char **argv) {
Integer a(atoi(argv[1])), b(atoi(argv[2]));
Integer c = a + b; // Line 20
std::cout << c;
}
Note the line 20
there--it becomes important below.
Now, let's compile it up and see what code the compiler produces. Using VC++ we get this:
[ normal "stuff" to set up entry to main
elided ]
; Line 19
mov rcx, QWORD PTR [rdx+8]
mov rdi, rdx
call atoi
mov rcx, QWORD PTR [rdi+16]
mov ebx, eax
call atoi
; Line 20
lea edx, DWORD PTR [rax+rbx]
; Line 21
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QEAAAEAV01@H@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
So even though we've created two Integer objects and added them using an overloaded operator that constructs and returns a third Integer object, the compiler has seen through all our subterfuge, and "realized" that what we're doing is just reading a couple of int
s using atoi
, adding them together, and printing out the int
we get as a result.
Having seen that, it eliminates the function call completely and doesn't call or return anything--it just reads two ints, adds them together, and prints out the result.
Using gcc the result is pretty much the same:
movq 8(%rbx), %rcx
call atoi ; <--- get first item
movq 16(%rbx), %rcx
movl %eax, %esi
call atoi ; <--- get second item
movq .refptr._ZSt4cout(%rip), %rcx
leal (%rsi,%rax), %edx ; <--- the addition
call _ZNSolsEi ; <--- print result
It's rearranged the code slightly, but ultimate does pretty much the same thing--all vestiges of our Integer
class have disappeared.
Let's compare that to what we get without using a class at all:
int main(int argc, char **argv) {
int a = atoi(argv[1]);
int b = atoi(argv[2]);
int c = a + b;
std::cout << c;
}
Using VC++, this produces the following:
; Line 5
mov rcx, QWORD PTR [rdx+8]
mov rdi, rdx
call atoi
; Line 6
mov rcx, QWORD PTR [rdi+16]
mov ebx, eax
call atoi
; Line 7
lea edx, DWORD PTR [rbx+rax]
; Line 8
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QEAAAEAV01@H@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
Other than the comments showing the line numbers from the original file, the code is precisely identical to what we got using the class.
I won't waste the space to copy and paste the result from doing the same with g++; it also produces identical code regardless of whether we use our class and overloaded operator to do the addition or not.