That code then becomes part of your project's code base, and you can override and change portions of it if desired, or use it as it comes from the wizard. The header contains some of the code, the implementation file contains some, and the IDL file contains some. Depending on the generated code's complexity and how many modifications you make, this can cause project maintenance problems. It becomes difficult to determine which code is wizard-generated and which has been modified by the programmer, especially if someone new picks up the code later. You can also kill the code through inadvertent keystrokes, and because you can't go back and rerun the wizard to patch up the code, it's difficult to fix errors.
Attributes attack the problem on the other end of the coding cycle.
By doing so, attributes avoid the previous code problems in several ways. And, because the compiler generates the code, you can't muck up the generated code accidentally. However, if you want to override a method on an interface generated by the attribute, you can simply add that code to your class. The compiler gives preference to your code and won't generate the boilerplate code. You can also mix attributes with existing ATL code, and the compiler will chain existing object maps and merge your IDL code with that generated by the attributes.