一段小代码,不少知识点

先看代码

   uint8_t i = 10;
   uint8_t& ref = i;
   uint32_t address = reinterpret_cast<uint32_t>(&i);
   std::cout << "uint8_t i address (method 1):" << std::hex << std::uppercase << (int)&i << std::endl;
   std::cout << "uint8_t i address (method 2):" << address << std::endl;

   address = reinterpret_cast<uint32_t>(&ref);
   std::cout << "reference address (method 1):" << (int)&ref << std::endl;
   std::cout << "reference address (method 2):" << address << std::endl;

   std::cout << std::dec << std::nouppercase  << std::endl;

输出:

uint8_t i address (method 1):28FF07
uint8_t i address (method 2):28FF07
reference address (method 1):28FF07
reference address (method 2):28FF07

 

知识点:

1. (int)() 与 reinterpret_cast, 那个更加安全一点?一般来说是reinterpret_cast, 其实C style cast 更好一点。同时对于muttiple inheritence你得小心, 看下面的例子。

2. std::hex,按16进制输出

3. std::uppercase, std::nonuppercase,把输出设为大写/小写

4. reference 是没有另外开辟存储地址

 

#ifndef CASTBASE_H_
#define CASTBASE_H_
#include <algorithm>

/**
 * @class CastBaseC
 * @brief
 */
class CastBase1C
{
public:
   /**
    * @brief Constructor
    */
   CastBase1C() = default;

   /**
    * @brief Destructor
    */
   virtual ~CastBase1C() = default;

   /**
    * @brief Set copy constructor as delete to prevent unintentional creation
    */
   CastBase1C(const CastBase1C& iValue) = delete;

   /**
    * @brief Set copy assignment as delete to prevent unintentional creation
    */
   const CastBase1C& operator=(const CastBase1C& iValue) = delete;

   void SetValue1(uint8_t iValue) {mValue1 = iValue;};
   uint8_t GetValue1(void) {return mValue1;};
private:
   uint8_t mValue1;
};

class CastBase2C
{
public:
   /**
    * @brief Constructor
    */
   CastBase2C() = default;

   /**
    * @brief Destructor
    */
   virtual ~CastBase2C() = default;

   /**
    * @brief Set copy constructor as delete to prevent unintentional creation
    */
   CastBase2C(const CastBase2C& iValue) = delete;

   /**
    * @brief Set copy assignment as delete to prevent unintentional creation
    */
   const CastBase2C& operator=(const CastBase2C& iValue) = delete;

   void SetValue2(uint8_t iValue) {mValue2 = iValue;};
   uint8_t GetValue2(void) {return mValue2;};
private:
   uint8_t mValue2;
};


class CastSubC:public CastBase1C, public CastBase2C
{
public:
   CastSubC() = default;
   virtual ~CastSubC() = default;
   void SetValue3(uint8_t iValue) {mValue3 = iValue;};
   uint8_t GetValue3(void) {return mValue3;};
private:
   uint8_t mValue3;
};


#endif /* CASTBASE_H_ */
void CastTest(void)
{
   CastSubC sub;
   sub.SetValue1(10);
   sub.SetValue2(200);
   sub.SetValue3(30);
   CastBase2C* ex1 = reinterpret_cast<CastBase2C *>(&sub);
   CastBase2C* ex2 = (CastBase2C*)(&sub);
   CastBase2C* ex3 = static_cast<CastBase2C *>(&sub);
   std::cout << "reinterpret_cast:\t" << ex1 << "\n";
   std::cout << "C-style cast:\t\t" << ex2 << "\n";
   std::cout << "no cast:\t\t" << &sub << "\n";
   std::cout << "static_cast:\t\t" << ex3 << "\n";

   std::cout << "ex1.GetValue2 = " << static_cast<int>(ex1->GetValue2()) << "\n";
   std::cout << "ex2.GetValue2 = " << static_cast<int>(ex2->GetValue2()) << "\n";
   std::cout << "ex3.GetValue2 = " << static_cast<int>(ex3->GetValue2()) << "\n";


   CastSubC* back1 = reinterpret_cast<CastSubC*>(ex1);
   CastSubC* back2 = (CastSubC*)(ex2);
   CastSubC* back3 = static_cast<CastSubC*>(ex3);
   std::cout << "back reinterpret_cast back1.GetValue1 = " << static_cast<int>(back1->GetValue1()) << "\n";
   std::cout << "back reinterpret_cast back1.GetValue2 = " << static_cast<int>(back1->GetValue2()) << "\n";
   std::cout << "back reinterpret_cast back1.GetValue3 = " << static_cast<int>(back1->GetValue3()) << "\n\n";

   std::cout << "back C-style cast back2.GetValue1 = " << static_cast<int>(back2->GetValue1()) << "\n";
   std::cout << "back C-style cast back2.GetValue2 = " << static_cast<int>(back2->GetValue2()) << "\n";
   std::cout << "back C-style cast back2.GetValue3 = " << static_cast<int>(back2->GetValue3()) << "\n\n";

   std::cout << "back static_cast back3.GetValue1 = " << static_cast<int>(back3->GetValue1()) << "\n";
   std::cout << "back static_cast back3.GetValue2 = " << static_cast<int>(back3->GetValue2()) << "\n";
   std::cout << "back static_cast back3.GetValue3 = " << static_cast<int>(back3->GetValue3()) << "\n\n";
}

 

 

输出结果看出reinterpret_cast在多个继承时要小心。

reinterpret_cast: 0x28fee8
C-style cast: 0x28fef0
no cast: 0x28fee8
static cast: 0x28fef0
ex1.GetValue2 = 10
ex2.GetValue2 = 200
ex3.GetValue2 = 200
back reinterpret_cast back1.GetValue1 = 10
back reinterpret_cast back1.GetValue2 = 200
back reinterpret_cast back1.GetValue3 = 30

back C-style cast back2.GetValue1 = 10
back C-style cast back2.GetValue2 = 200
back C-style cast back2.GetValue3 = 30

back static_cast back3.GetValue1 = 10
back static_cast back3.GetValue2 = 200
back static_cast back3.GetValue3 = 30

 

对于cast, 这里有一个很好的总结:

https://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used

static_cast is the first cast you should attempt to use. It does things like implicit conversions between types (such as int to float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones). In many cases, explicitly stating static_cast isn't necessary, but it's important to note that the T(something) syntax is equivalent to (T)something and should be avoided (more on that later). A T(something, something_else) is safe, however, and guaranteed to call the constructor.

static_cast can also cast through inheritance hierarchies. It is unnecessary when casting upwards (towards a base class), but when casting downwards it can be used as long as it doesn't cast through virtual inheritance. It does not do checking, however, and it is undefined behavior to static_cast down a hierarchy to a type that isn't actually the type of the object.


const_cast can be used to remove or add const to a variable; no other C++ cast is capable of removing it (not even reinterpret_cast). It is important to note that modifying a formerly const value is only undefined if the original variable is const; if you use it to take the const off a reference to something that wasn't declared with const, it is safe. This can be useful when overloading member functions based on const, for instance. It can also be used to add const to an object, such as to call a member function overload.

const_cast also works similarly on volatile, though that's less common.


dynamic_cast is almost exclusively used for handling polymorphism. You can cast a pointer or reference to any polymorphic type to any other class type (a polymorphic type has at least one virtual function, declared or inherited). You can use it for more than just casting downwards -- you can cast sideways or even up another chain. The dynamic_cast will seek out the desired object and return it if possible. If it can't, it will return nullptr in the case of a pointer, or throw std::bad_cast in the case of a reference.

dynamic_cast has some limitations, though. It doesn't work if there are multiple objects of the same type in the inheritance hierarchy (the so-called 'dreaded diamond') and you aren't using virtual inheritance. It also can only go through public inheritance - it will always fail to travel through protected or private inheritance. This is rarely an issue, however, as such forms of inheritance are rare.


reinterpret_cast is the most dangerous cast, and should be used very sparingly. It turns one type directly into another - such as casting the value from one pointer to another, or storing a pointer in an int, or all sorts of other nasty things. Largely, the only guarantee you get with reinterpret_cast is that normally if you cast the result back to the original type, you will get the exact same value (but not if the intermediate type is smaller than the original type). There are a number of conversions that reinterpret_cast cannot do, too. It's used primarily for particularly weird conversions and bit manipulations, like turning a raw data stream into actual data, or storing data in the low bits of an aligned pointer.


C-style cast and function-style cast are casts using (type)object or type(object), respectively. A C-style cast is defined as the first of the following which succeeds:

  • const_cast
  • static_cast (though ignoring access restrictions)
  • static_cast (see above), then const_cast
  • reinterpret_cast
  • reinterpret_cast, then const_cast

It can therefore be used as a replacement for other casts in some instances, but can be extremely dangerous because of the ability to devolve into a reinterpret_cast, and the latter should be preferred when explicit casting is needed, unless you are sure static_cast will succeed or reinterpret_cast will fail. Even then, consider the longer, more explicit option.

C-style casts also ignore access control when performing a static_cast, which means that they have the ability to perform an operation that no other cast can. This is mostly a kludge, though, and in my mind is just another reason to avoid C-style casts.

 还有一好文章分享:

EXP14-CPP. Do not use reinterpret_cast on pointers to class objects with multiple inheritence

 

posted on 2018-02-01 09:57  荷树栋  阅读(150)  评论(0编辑  收藏  举报

导航