The value of the expression c1+c2 is ignored by your code, as you are not storing it anywhere. At most, the compiler will print some warning messages. To supress such warning messages, you could write :
(void)(c1+c2); //casting to void suppresses the warning messages!
See this:
The real issue with your code..
However, in your code, the implementation of operator+ is not semantically correct. To understand that consider this,
 int a=10;
 int b=5;
then, do you expect a+b to change the value of a? Should a become 15? No.
If you want that, then you would write a+=b instead. But in your code, c1+c2 behaves equivalent to the semantic of c1+=c2, as you're updating the value of this->real and this->imag in your implementation of operator+, which is not correct, semantically.
So the first fix is this:
complex complex::operator + (const complex& c) const
{                            
  complex result(c); //make a copy of c
  result.real += this->real; //add
  result.imag += this->imag; //add
  return result;
}
Now, this is semantically correct.
That said, there is still few things to be noted. When you write c1+c2, do you think the operation + is applied on either of the object? No. It doesn't apply on any of them, yet the member function operator+ gets invoked on c1 object which becomes this pointer inside the function. Why should it be invoked on c1 (or for that matter c2) if the operation doesn't apply on it?
This analysis makes it clear that operator+ shouldn't be a member function of the class. It should be a non-member function instead, and the signature then would be:
complex operator+(const complex &a, const complex &b);
But there is a small problem: in the computation of a+b, it needs to access to the private members of the class (real and imag are private members). So the solution is, operator+ should be implemented in terms of operator+=, and the latter should be added as a member function to the class, because the operation += in the expression a+=b does apply on a, as it modifies its value.
So here is my implementation of both operators:
class complex
{
  //...
  public:
    //member function
    complex& operator+=(const complex & c)
    {
          real += c.real; //same as: this->real+=c.real; this is implicit
          imag += c.imag; //same as: this->imag+=c.real; this is implicit
          return *this;
    }
};
//non-member function (its non-friend as well)
complex operator+(const complex &a, const complex &b)
{
    complex result(a); //make copy of a by invoking the copy-constructor
    result += b;  //invokes operator+
    return result;
}
Or you could join last two statements as:
complex operator+(const complex &a, const complex &b)
{
    complex result(a); //make copy of a by invoking the copy-constructor
    return result += b;  //invokes operator+, and then return updated 'result'
}
But there is another way to make copy. Why pass both arguments by reference? Passing the first argument by value would make the copy we need. So a better implementation would be this:
complex operator+(complex a, const complex &b)
{               //^^^^^^^^^ pass-by-value
    a += b; //a is a copy, after all - we can modify it!
    return a;
}
Hope that helps.