TITLE: the copy-assignment operator (Newsgroups: comp.lang.c++.moderated) PROBLEM: vavasis@CS.Cornell.EDU (Stephen Vavasis) In a couple of earlier message, I raised the following question. Suppose B is a base class and D is derived from B. Suppose that there is an operator B& D::operator=(const B&) defined by the user. Suppose that there are two items a,b of static type D, and the statement "a=b;" is encountered. Should this statement invoke the user-defined operator=() (because of the available implicit cast from const D& to const B&) or should this statement bypass the user's op= and invoke the default copy-assignment that is constructed by the compiler? According to Stephen Clamage, the standard-conforming behavior is to invoke the default rather than user-defined op=. I wrote a program to test this, and tried it on several compilers. class Derived : public Base { public: Derived& operator=(const Base& x) { data = x.data; return *this; } Derived() { } ~Derived() { } }; b = a; // I want this statement to invoke Derived::operator=(const Base&) So I guess there is some disagreement among compilers how to handle this situation. RESPONSE: clamage@Eng.Sun.COM (Steve Clamage), 28 Apr 96 As I said in my earlier article, the ARM was not at all clear (and was self-contradictory) about what should happen, and different compilers did different things. The draft standard was recently clarified, and defined the concept of copy-assignment (and copy-construction) and what exactly constitutes a copy-assignment operator (and copy constructor). Not all compilers yet conform to the clarified definitions. The reason for the rule is to ensure uniform behavior on copying, which is, after all, predefined in the language. If you assign a T to a T, the copy always occurs with T::operator=(T&). If you don't want the behavior of the predefined copy-assignment operator, you always write your own. Suppose that were not the rule: class base { ... operator int(); ... }; class derived : public base { ... derived& operator=(int); // but no user-defined operator=(const derived&); }; derived d1, d2; ... d1 = d2; // what happens here? A derived has a standard conversion to base, and a base can be converted to an int, so should this assignment convert d2 to an int and assign the int to d1? Under your preferred rule, that should happen, but is unlikely ever to be what the programmer wanted or expected. (I don't think any of your dissenting compilers would do this, but that just means they don't have a consistent model for copy assignment.) Thus, if you ever have a special assignment operator, you would also have to write the copy-assignment operator every time to avoid unpleasant surprises. Under the existing rule, you must write the copy-assignment operator only when you do not want the predefined behavior. In your case, you add a one-line inline function which has zero runtime overhead. It also seems odd to have a special assignment operator to copy a base to a derived. Should the default language rule cater to the unusual case and make the usual cases more difficult to program? Finally it seems to me that having a special assignment operator derived::operator=(const base&); does not imply that I want to use it to copy a derived to a derived. What about the derived members that would not be so copied? It makes more sense IMHO to have to say explicitly that I want to ignore the derived members in making a copy (if that is what I want). I hope you are not thinking that maybe the compiler should look at the derived class, and if the derived class has no nonstatic data members but does have the assignment operator as above, it should use it instead of generating one. A defensive programmer would then have to write an explicit copy-assignment operator for every class without fail. The non-obvious connection among special assignment operators, type conversion operators, and the default copy semantics would make it dangerous to rely on getting the compiler-generated copy-assignment operator.