When creating interfaces in C++, code space can be saved by breaking classes into their smallest possible interfaces. This means breaking UART and SPI classes at least into a transmit and receive object. I2C probably not since it is bi-directional in nature.