It mostly depends on what \example is supposed to do. The standard way is to delay reading the argument: if you expect that \test can have both \example and \example^ in its argument, define it as
\def\test{\begingroup\catcode`^=11 \dotest}
\def\dotest#1{#1\endgroup}
so the category code change happens before the argument is grabbed and catcodes frozen. Of course this has the limitation that \test cannot be itself used in the argument to another command.
A different strategy is to have just one \example macro:
\def\example{\futurelet\next\doexample}
\def\doexample{\ifx^\next\let\next\examplehat
\else\let\next\examplenohat\fi\next}
\def\examplehat^#1#2{this is \#1: #1. this is \#2: #2}
\def\examplenohat#1#2{No hat (#1,#2)}
No category code change.
Full code:
\def\example{\futurelet\next\doexample}
\def\doexample{\ifx^\next\let\next\examplehat
\else\let\next\examplenohat\fi\next}
\def\examplehat^#1#2{this is \#1: #1. this is \#2: #2}
\def\examplenohat#1#2{No hat (#1,#2)}
\example25
\example^25
\def\test#1{#1}
\test{\example25}
\test{\example^25}
\bye

With \scantokens we still have to delay grabbing the argument or it would already be tokenized at the category code change and control sequences formed.
\begingroup
\catcode`^=11
\gdef\example^#1#2{this is \#1: #1. this is \#2: #2}
\endgroup
\def\example#1#2{No hat (#1,#2)}
\def\test{\begingroup\catcode`^=11 \dotest}
\def\dotest#1{\scantokens{#1\noexpand}\endgroup}
X\test{\example25}X
X\test{\example^25}X
\bye

\scantokenswhich is not in Knuth TeX). – egreg Nov 20 '15 at 21:43