I must admit that, at first, I didn't carefully read OPs question.
Encoding a range from A to Z, a std::map<> (as suggested in P.Ws answer) is able to do it but seems to me a bit over-engineered. An array is fine to do this job as well and surely faster. (Access is O(1) instead of O(ld(N)).)
So, encoding could look like this:
char encode(char c)
{
  static const char cMap[] = {
    /* A= */ 'O',
    /* B= */ 'M',
    /* C= */ 'V',
    /* D= */ 'H',
    /* E= */ 'J',
    /* F= */ 'R',
    /* G= */ 'T',
    /* H= */ 'L',
    /* I= */ 'Y',
    /* J= */ 'A',
    /* K= */ 'C',
    /* L= */ 'K',
    /* M= */ 'X',
    /* N= */ 'E',
    /* O= */ 'W',
    /* P= */ 'U',
    /* Q= */ 'B',
    /* R= */ 'G',
    /* S= */ 'S',
    /* T= */ 'Q',
    /* U= */ 'F',
    /* V= */ 'N',
    /* W= */ 'Z',
    /* X= */ 'I',
    /* Y= */ 'P',
    /* Z= */ 'D'
  };
  return c >= 'A' && c <= 'Z'
    ? cMap[c - 'A'] // range ['A', 'Z'] to range [0, 25]
    : '?';
}
Reading twice, I realized the decrypt – oops.
However, it does work as well in reverse direction:
char decode(char c)
{
  static const char cMap[] = {
    /* A= */ 'J',
    /* B= */ 'Q',
    /* C= */ 'K',
    /* D= */ 'Z',
    /* E= */ 'N',
    /* F= */ 'U',
    /* G= */ 'R',
    /* H= */ 'D',
    /* I= */ 'X',
    /* J= */ 'E',
    /* K= */ 'L',
    /* L= */ 'H',
    /* M= */ 'B',
    /* N= */ 'V',
    /* O= */ 'A',
    /* P= */ 'Y',
    /* Q= */ 'T',
    /* R= */ 'F',
    /* S= */ 'S',
    /* T= */ 'G',
    /* U= */ 'P',
    /* V= */ 'C',
    /* W= */ 'O',
    /* X= */ 'M',
    /* Y= */ 'I',
    /* Z= */ 'W'
  };
  return c >= 'A' && c <= 'Z'
    ? cMap[c - 'A'] // range ['A', 'Z'] to range [0, 25]
    : '?';
}
The re-ordering of array values was a bit tedious – I could've done it using sort.