If you're going to capture the Tcl interpreter's standard output (and standard error; some important messages go there!) then you must run the Tcl interpreter in a sub-process, communicating with the outer Qt/C++-based process via pipes. (You should be able to find how to do that in general by searching Stack Overflow…)
Tcl-specific details: You'll really want to make sure that the Tcl interpreter does:
fconfigure stdout -buffering line
This is because in non-interactive mode (such as when being used over a pipe) Tcl uses full buffering for its standard output. You want line buffering (or perhaps none for unbuffered output) so that you can see values immediately when they're written out.
You will probably also want to run a custom REPL (assuming Tcl 8.5 or 8.6):
fconfigure stdout -buffering line
while {[gets stdin line] >= 0} {
set code [catch $line msg opt]
puts [list $code $msg $opt]
}
The way this writes the result back is as a Tcl list (not usually too hard to parse) which contains the result code (usually 0 for OK or 1 for ERROR) the result message/data, and a key/value dictionary that describes additional “interesting” stuff like stack traces in the case of errors.