Contracts cannot read storage of other contracts. What they can do is call other contracts and get a return value. Thus, if the other contract provides a "getter" they can get storage data indirectly.
Note that "privacy" is not the reason for this. Everything on the blockchain is public, irrespective of the internal access model.
In theory, another indirect way of "reading" a storage slot of another contract is having an external party provide a Merkle proof for it that the contract verifies against a recent blockhash. However, that's relatively hard to implement, would cost a lot of gas, is asynchronous, and probably not worth the effort.