> The problem with copy pasted code is that you can forget to push fixes to both copies.
That's a problem with manually copy-pasted code. Copy-paste automation solves this particular problem, but it creates others, like a combinatorial explosion of definitions that are similar enough to tempt humans to conflate them, but different enough to make such conflation logically unsound.
> inheritence usually does much less copy pasting under the hood. Instead, it makes use of vtables to actually reuse the binary.
I'm not talking about the implementation. Indeed, as you observe, using vtable pointers is a common technique to eliminate or reduce the need to make physical copies.
But, at the abstraction level, inheritance is fundamentally a copy-paste mechanism between two definitions. When a definition Foo inherits from another definition Bar, the parts of Bar that Foo retains (doesn't override) are copied into Foo's definition. In addition, sometimes an implicit coercion from Bar into Foo is provided. However, you can't conclude that Foo is really a specialization of Bar. This isn't true if Foo overrides any inherited behavior from Bar. In other words, the Liskov substitution principle actually matters!
> but for templates, macros, compiler optimizations, inheritence,
Of course, from this point of view, macros and templates are just more powerful forms of copy-paste automation. Compiler optimizations are an implementation detail, not a language construct, and thus need a separate discussion.
> and all the other forms of abstraction that allow you to not repeat code.
Abstraction is actually about controlling the visibility of implementation details. It's a powerful organization tool, even if you don't actually intend to reuse any code.
On the other hand, code reuse can be achieved by various means, ranging from principled (parametric polymorphism, hygienic macros) to ad-hoc (templates, unhygienic macros), with inheritance falling somewhere in between.