The private attribute of class members apply on a class-wide basis, not a per-object basis. All member functions (and friends) of class A can access any private members of any instance of A (as well as any private static members of class A). If that wasn't true, your code would not even compile.
The catch is that, in the call obj1.add(obj2), obj2 is being passed
by value to add(). That means the add() function sees
a copy of obj2, not obj2 itself. It therefore changes the copy, not the original. The copy is destroyed immediately after the function returns, and data is not copied back into obj2 inside main().
If you want the change of obj.x in the add() to be visible to the caller - i.e. for obj1.add(obj2) to directly modify obj2 - then change the add function so it accepts a reference argument.
Code:
void add( A &obj ) // etc