I am wondering about the efficiency of the implementation of the supply capping mechanism in ERC20Capped.sol.
It seems each time a transfer is made, the _beforeTokenTransfer function will be called to verify that the cap is not exceeded. Whereas it would seem more natural to inline this verification within the functions that may actually increase totalSupply. Eg in the standard case the _mint function.
Incidentally, the error messages "ERC20: mint to the zero address", "ERC20: burn from the zero address" look inverted to me, one burns (mints) to (from) the zero address.
I think it is ok for you to write your own capped contract like so, but for the OpenZeppelin team, it seems like not, cause they want to keep a flexible approach, the ERC20.sol is a basic contract and the ERC20Capped.sol is one of the many derivatives of ERC20.sol, in addition to this there are ERC20Burnable.sol, ERC20Pausable.sol and so on, so for this capped contract, you should re-write your own logic only in capped contract to achieve your purpose.
I am not sure what you mean here. The check in _mint is to prevent minting to the zero address and the check in _burn is to prevent burning from the zero address.
You are right that fact that the cap protection hooks into _beforeTokenTransfer slightly increasses the cost of all transfers because of the if (from == address(0)) check.
We usually prefer not to overload function and use the hook mechanism whenever possible. This is done because child contracts might have to resolve the overloading, which might be disturbing for some users. However, in this case, overloading clearly is the most gas efficient way, and thus feels like the better way.
In the future, when you noticed design pattern that could improve gas efficiency, feel free to raise an issue on github, and we will see how we can improve that.