Using friend operator overload should do the trick for you and is a common way to define binary operators, just add:
friend sample operator+(const sample& a, const sample& b); //in class
sample operator+(const sample& a, const sample& b) { //outside the class
    return sample(a.x + b.x);
}
If you want it to remain a member, (which has downsides in some rare scenarios, and no upsides), you have to make the operator a const function:
sample operator+(sample s) const; //in class
sample sample::operator+(const sample& b) const { //outside the class
    return sample(this->x + b.x);
}
Either of these will allow operator chaining.  The reason your previous s = s + s1 + s2 was failing, is that the s + s1 would execute and return a temporary sample object.  Then, it would attempt to add s2 to that sample.  However, temporaries can only be const references[1], and as such, can only use const member functions.  Since your operator+ member function is not a const function, you cannot use that function on the const temporary.  Note that to make it const, I had to rewrite it, since your version modifies the object on the left side of the +.
[1]with exceptions aren't particularly relevant here, namely rvalues