The standard library in C++ does not provide a way to do what you want. However, you can use a third party library, like boost::process, which will make the communication part between your program and the sub-processes pretty portable. If you want to execute built-in shell commands, or commands using the shell, you will still need to deal with differences in the shells used on the different platforms.
The boost::process library contains a lot of different ways of creating and communicating with sub processes (reference), both synchronously and asynchronously, so browse through the reference page to get a feeling for what it can do.
Here's a simple example that uses boost::process::system to run the command dir in the directory desktop and collects the output from that command. It does not use the shell (which should generally be avoided) but uses boost::process::search_path to find the command (in your PATH) and executes the command directly without involving a shell:
#include <boost/process.hpp>
#include <boost/process/start_dir.hpp>
#include <iostream>
#include <string>
int main() {
    namespace bp = ::boost::process;
    bp::ipstream out;
    bp::ipstream err;
    bp::system(bp::search_path("dir"),
               bp::start_dir = "./desktop",
               bp::std_out > out,           // collect stdout in out
               bp::std_err > err,           // collect stderr in err
               bp::std_in < stdin);         // for commands reading from stdin
    // display what was collected on stdout and stderr:
    std::string line;
    std::cout << "stdout capture:\n";
    while(std::getline(out, line)) {
        std::cout << '[' << line << "]\n";
    }
    std::cout << "\nstderr capture:\n";
    while(std::getline(err, line)) {
        std::cout << '[' << line << "]\n";
    }
}
Note: You need to link with boost_filesystem and boost_atomic for this example to work.