static_cast, C-style cast and functional notation: battle of the titans in C++
\n\nHello, fellow programmer! If you've ever written in C++, you've probably wondered: "Why do all these gurus insist on using static_cast<int>(x) instead of the good old (int)x or int(x)? After all, the result is the same!"
Spoiler: the result is not always the same, and the difference can cost you hours of debugging, and sometimes even program safety. In this article, we'll break down a popular Stack Overflow question (with thousands of views) and explain in detail why modern C++ (starting from C++11 and later) strongly recommends using static_cast.
\n\nWe won't just list the rules; we'll show them with live examples you can run. Let's go!
\n\n1. Visual "noise" and code search
\n\nThe problem with C-style cast
\n\nImagine a line of code:
\n\nint result = (int)someDoubleValue * (int)anotherDoubleValue;\n\nHow many type casts are here? Two. But try to find them with your eyes in half a second. Now imagine you have 5000 lines of code, and half of them contain such parentheses. It's a nightmare for code review.
\n\nNow let's look at the same code with static_cast:
int result = static_cast<int>(someDoubleValue) * static_cast<int>(anotherDoubleValue);\n\nIt's immediately obvious: "Aha, here we are deliberately truncating double to int." static_cast acts as a documenting comment. It screams: "I know what I'm doing! This is a conscious type cast!"
\n\nBonus for grep and IDE
\n\nTry to find all places in a project where C-style cast is used. You'll be searching for just ) or ( — that's impossible. But static_cast can be found with a single command grep -r "static_cast". Your IDE will highlight them, and you can quickly scan all dangerous spots.
2. Safety: the compiler is your friend, not your enemy
\n\nTypical beginner mistake
\n\nSuppose you want to cast a pointer to a base class into a pointer to a derived class. C-style cast will do it silently, even if the class hierarchy is unrelated:
\n\nclass Base { /* ... */ };\nclass Derived : public Base { /* ... */ };\nclass Unrelated { /* ... */ };\n\nBase* basePtr = new Derived;\nUnrelated* badPtr = (Unrelated*)basePtr; // The compiler stays silent!\n// Now you have UB (undefined behavior) when accessing badPtr\n\n\nThis is called reinterpret_cast, and C-style cast performs it without warning. static_cast will produce a compilation error in such a situation:
Unrelated* badPtr = static_cast<Unrelated*>(basePtr); // Compilation error!\n// error: invalid static_cast from type 'Base*' to type 'Unrelated*'\n\n\nThe compiler is your shield. C-style cast is like turning off all safety systems in a car and hoping you don't crash.
\n\nDowncasting pointers in a hierarchy
\n\nC-style cast allows downcasting without runtime type checking. static_cast also allows it, but at least it checks that the classes are in the same inheritance hierarchy. For safe downcasting with RTTI checking, use dynamic_cast — but that's another story.
3. Control over what you're doing
\n\nThree different casts in one set of parentheses
\n\nC-style cast is a Swiss Army knife that can do three different things:
\n- \n
- static_cast (ordinary casting between numeric types or up/down a hierarchy) \n
- const_cast (removing constness) \n
- reinterpret_cast (reinterpreting the bit representation) \n
Here's an example that shocks many:
\n\nconst