top of page
altaybrusan

Casts in C++

Updated: Aug 3, 2022





Static Cast

static_cast is used for code clearance. The functionality of it is almost same as the the implicit conversion.

Example


#include <iostream> 
using namespace std;

int main(int argc, char argv[])
{
    float _floatValue{ 1.3 };
    int _integerValue{ 1 };

    _integerValue = _floatValue;
    _integerValue = static_cast<int>(_floatValue);

    return 0;
}

in this example both assignment do the same thing; however, using static_cast, we emphasize there is a type casting here!




static cast happens at compile time (not at run time)





#include <iostream> 
#include <string>
using namespace std;

class Integer {
private:
    int m_number;
public:
    Integer(int number):m_number{number}
    {

    }
    operator string()
    {
        return to_string(m_number);
    }
};

int main(int argc, char argv[])
{
    Integer _object{ 8 };
    // implicit conversion
    string _str = _object;
    _object = 40;
    //explicit conversion
    string _str2 = static_cast<string>(_object);
    _object = static_cast<Integer>(50);
}

in line

string _str = _object;

In this example, we convert an object of type Integer into string!!! How does it happens? It happens because of the conversion operator.

These conversions make your code a little ambiguous. By means of static cast we can be sure anybody always immediately understand the code.

static cast is restrictive. It avoids to cast from derived class to private base and issues a compile time error.


class Base {};
class Derived:Base{};
int main(int argc, char argv[])
{
    Derived _drived;
    Base* _basePtr1 = (Base*)&_drived; //no problem
    Base* _basePtr2 = static_cast<Base*>(&_drived); //compile-time error
    Base _baseObj = static_cast<Base>(_drived); // compile time error
}

to solve this, the derived class should derived public.

class Derived:public Base{};   

Pointer interchange is a tricky situation! The following example shows this condition.



class Base {};
class Derived1 :public Base {};
class Derived2:public Base{};
int main(int argc, char argv[])
{
    Derived1 _d1;
    Derived2 _d2;

    Base* base1 = static_cast<Base*>(&_d1);
    Base* base2 = static_cast<Base*>(&_d2);
    
    Derived1* drived1Ptr = static_cast<Derived1*>(base2);
    Derived2* drived2Ptr = static_cast<Derived2*>(base1);
}

In this example the 'drived1Ptr' point to an object of type Drived2! So, static cast is not secure all times.

The common application of static is convert to/from void*.


Static Cast

this cast is very useful for removing const-ness. The main application of this type cast is to call functions ( which may not follow the best practices) and accept non-const inputs however, the variables we have in our hand are const. To discuss this issue in common application, consider variable (storage) and a pointer (direct) which is used to access the variable. If the storage itself is const, then the best practice is to not to use static cast at all! However, if we now for sure, that the variable is not const, but the pointer is const, then we can remove the const-ness from the pointer.


int main(int argc, char argv[])
{
    const int _storage = 10;
    const int* _directPtr = &_storage;
    //...
    int* _indirectPtr = const_cast<int*>(_directPtr);
    *_indirectPtr = 15;    
    cout <<"indirect access after manipulation:" << *_indirectPtr << endl 
        <<"direct access before manipulation:" << _storage << endl;

}

In this example, the _storage is const so we are not supposed to change it. Now suppose we created a const pointer _directPtr to access to _storage. Lets say somewhere in the project we, need to call a function (from a 3rd- party library) that accepts int*. In this situation, we may use const_cast to remove the const from the _directPtr and generate _indirectPtr. This new born pointer is not safe to be used! The reason is the point the pointer (_indirectPtr) is pointing at (_storage) is const. So, in this situation the behavior is unpredicted. In Visual Studio C++, using _indirectPtr we can manipulate the _storage. But a tricky situation might happens! The output of this example is




indirect access after manipulation:15
direct access before manipulation:10  

Why 10 is there? it is because, at compile time the compiler calculate and insert the const variable values, which in this case its value is changed at runtime.




0 views0 comments

Recent Posts

See All

smart pointers

The code we just described is fully functional, but, it can be strengthened, specifically with the function, AlbumDao::albums(). In this...

Comments


bottom of page