QPSK using Root Raised Cosine Filter
The way I prefer to look at it is to think of the QPSK signal as a complex envelope; that is, as a baseband signal. In this representation, you have a single basis, but the amplitudes are allowed to be complex.

So, let $p(t)$ be a root-raised cosine pulse such that $$\int_{-\infty}^\infty p(t-lT_p)p(t-mT_p) = \begin{cases}1\textrm{, if $l=m$}\\ 0\textrm{, if $l\neq m$,}\end{cases}$$ where $R_p=1/T_p$ is the pulse rate. Now you can think of the QPSK signal $s(t)$ as $$s(t)=\sum_k a_kp(t-kT_p)$$ where $a_k$ are complex symbols taken from a QPSK constellation. As you can see, you only need one set of real orthonormal pulses. The complex amplitudes $a_k$ can be recovered by matched filtering.

Another way to look at it is that you have two basis, one real and the other imaginary (the set $jp(t)$).