Maybe the results of a function call may not be completely understood by the programmer, but from the syntactical point of view it is easy to figure out what is going on in the program.

And, to put it clearly, the problem is not that the function or class is doing something we don’t know. The problem is mostly in trying to figure out what is happening in a given line of code. In C is very easy to figure out what is being called (up to macros): just read the manual for the functions being used and you will have a good idea of what is being executed.

After sorting through this pile of caveats, what point remains?

In C++, on the other hand, a large number of things can be happening in a single line: an overloaded operator, a type conversion, a template instantiation, an overridden function in one of a dozen of classes, a constructor called in some part of the hierarchy, in some namespace…

It isn't that hard to figure things out in C++. An operator is an operator is an operator; there are a fixed list of symbols that can be used as operators. An operator may be defined by the language, or it may be user-defined. Template instantiations are visible. (I don't recall whether you need <> when a template has default parameters, but in that case it just acts like a regular class anyway.) Constructors are just functions that get called when objects are created. Granted, you can create a confusing situation by using multiple inheritance, but multiple inheritance is one of C++'s nuclear options, like macros in C. (I suspect the author would blame C++ for having multiple nuclear options instead of just one.)

Namespaces are very nice for organizing code, and almost every language has some equivalent mechanism. I think the burden is on the author to argue that everyone else is wrong about this.

I'll give him type conversions. Those can be tricky and unexpected, and it's backwards that you have to declare your constructors "explicit" to prevent them from being used in type conversions. It should be the other way around; you should have to declare constructors "implicit" in the rare cases where you want to enable conversion. However, once you're paying attention (and I agree you shouldn't have to), it isn't difficult to figure out when type conversion is happening, simply because you'll see that an argument of a certain type is being passed to a function that cannot take that type. If it compiles, then a type conversion is being invoked. Where people get really confused is when they're trying to take advantage of type conversion, but the conversion they think is happening isn't actually happening. Personally, I've rarely messed with it, so I don't care.

You have to be smart enough to figure out what is going on

I can't tell you how much it hurts my head to read C or how many times I've thought I just wouldn't be smart enough to be a C programmer. It's a different kind of thinking. I'd much rather read a few hundred lines of C++ full of tricky constructs than a few thousand lines of C full of buffer allocations and deallocations and return value checks. My brain overflows and I can't keep track of the high-level shape of the code. Trying to figure out how C code works when I don't already know its purpose is very hard for me. To each his own, I guess.