There's something unintuitive about Bitcoin transaction SigOp counting. Normally, the signature count of a block is calculated by looking at the scriptPubKey of each transaction and counting how many OP_CHECKSIG operations it contains. In other words, the SigOp count is gotten by looking at how many outputs you create, not how many inputs you redeem.
However, you obviously can't see how many operations a P2SH script does by looking at its hash. Instead, the transaction that spends the P2SH script "pays" for it.
The somewhat awkward thing is that you can't tell if a scriptSig is spending a P2SH output unless you look up the outpoint it's spending.
Why doesn't CheckBlock() just include the P2SH sig op count to avoid code duplication between the two methods?
I don't think it's for backwards compatibility. While ConnectBlock doesn't count P2SH SigOps for transactions that appear to be P2SH but aren't, that logic could be implemented in CheckBlock instead.
I don't think it's for efficiency. Rejecting blocks with too many SigOps isn't very common, since it takes about seven thousand dollars of electricity to make a block. I suspect that you could remove the SigOp check from CheckBlock for a very minor performance increase.
I think it's partially because it would be irritating to change. Getting the P2SH SigOp count requires access to the CCoinViewCache object, which isn't passed to CheckBlock.