I'm new to solidity and trying to understand OpenZeppelin's Context contract. At the time of writing, the documentation says:
While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned).
This contract is only required for intermediate, library-like contracts.
I kind of understand at a high level that msg.sender can be different from the actual sender for a meta-transaction, but I do not understand how using Context's _msgSender() or _msgData() helps with that. Both functions are simply returning msg.sender and msg.data and they look no different from directly accessing msg.sender or msg.data.
OpenZeppelin's Ownable uses _msgSender() in its constructor and modifier onlyOwner() but I don't understand how that's different from hardcoding msg.sender.
A specific example where calling _msgSender() is different from msg.sender would be very helpful!