Unless I misunderstand what you want to achieve, you need an assignment operator for class , i.e. one that takes as the input:
What happened within your code (already explained in the answer of Bo Persson and comments there): in , you implemented an assignment operator that takes an instance of ; but in you assign an instance of ; the compiler saw no assignment operator for (the one that takes does not count), and so it generated one, which calls and then assignments for 's data members. If you defined the assignment as shown above, it would not happen and your operator would be called; notice that in this case assignments of and data members would not happen automatically.
A different situation is if you really wish to have an assignment from to , e.g. to use it with other derivatives of . Then the operator you defined will work, but in order to apply it to an instance of , you need to cast this instance to :
Needless to say that the operator you defined cannot easily access data members of specific to : e.g. to use you would need to "up-cast" to :
Short Answer: Yes you will need to repeat the work in D
If your derived class 'D' contains no new member variables then the default versions (generated by the compiler should work just fine). The default Copy constructor will call the parent copy constructor and the default assignment operator will call the parent assignment operator.
But if your class 'D' contains resources then you will need to do some work.
I find your copy constructor a bit strange:
Normally copy constructors chain so that they are copy constructed from the base up. Here because you are calling the assignment operator the copy constructor must call the default constructor to default initialize the object from the bottom up first. Then you go down again using the assignment operator. This seems rather inefficient.
Now if you do an assignment you are copying from the bottom up (or top down) but it seems hard for you to do that and provide a strong exception guarantee. If at any point a resource fails to copy and you throw an exception the object will be in an indeterminate state (which is a bad thing).
Normally I have seen it done the other way around.
The assignment operator is defined in terms of the copy constructor and swap. This is because it makes it easier to provide the strong exception guarantee. I don't think you will be able to provide the strong guarantee by doing it this way around (I could be wrong).
Even if you derive a class D from from X this does not affect this pattern.
Admittedly you need to repeat a bit of the work by making explicit calls into the base class, but this is relatively trivial.