I don't believe that it is accurate to say that C gives "more control" than C++. The near-superset functionality of C++ means that you can do anything in C++ that you can in C. There are some things that are more tedious in C++ (like the need to cast void* to assign to another type), but there are many things in C++ that I find to be conveniences (like not needing to typedef your structs to avoid writing struct Foo
everywhere you want a foo).
I feel that it is a good exercise to try to strip as many of the "advanced" C++ features out of your programming as possible, and to only use those the "complicated bits" (in terms of compiled code, not understanding the code) when you absolutely need them. Throwing away member functions, RTTI, and exceptions will get you a good way there.
As to your specific questions: everything leads to unpredictable machine code unless you know what that feature is doing. I, for one, consider the code generated by virtual functions to be one of the more straight-forward and obvious implementations of that feature. C gives you no additional access as "disguised assembler" than C++ does; you can do bit operations on both and (you can try to) write directly to memory anywhere you choose. In either language you can directly write machine code, too, just by casting an array of bytes to a function and calling it. This wouldn't be considered broadly portable, but if it's power you're after, C++ hides nothing from you.