【问题标题】:static_cast - what does conversion between compatible types mean?static_cast - 兼容类型之间的转换是什么意思?
【发布时间】:2011-10-14 07:30:52
【问题描述】:

我知道 static_cast 可以在基数和派生以及派生和基数之间转换。 dynamic_cast 将检查结果对象是否为“完整”对象。

dynamic_cast 使用 RTTI 功能。但是 static_cast 是如何工作的呢? “兼容类型”是什么意思?

我的问题实际上是关于兼容类型的含义。但我很高兴从帖子中学到了一些东西。此示例演示了编译器如何解释兼容类型。最后几行是最有趣的。注意有趣的结果。

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

class CBase { virtual void dummy() {} };
class CDerived: public CBase {  public: CDerived() : a(20) {} int a; };
class CDerived2: public CBase { public: CDerived2() : b(7) {} int b; };
class CDerived3: public CBase { public: CDerived3() : c('A') {} char c; };
class CNotDerived { int doit() const { return 9; } };

int main () {
  try {
      CBase * pba = new CDerived;
      CBase * pbb = new CBase;
      CDerived * pd;
      CNotDerived* pnot = new CNotDerived;
      CDerived2* pd2 = 0; 
      CDerived2* pdx = new CDerived2;
      CDerived3* pd3 = 0;


      pd = dynamic_cast<CDerived*>(pba);
      if (pd==0) cout << "Null pointer on first type-cast" << endl;   //ok

      pd = dynamic_cast<CDerived*>(pbb);
      if (pd==0) cout << "Null pointer on second type-cast" << endl;  //null ptr here

      pd = static_cast<CDerived*>(pbb);  //non-null pointer returned (not really what you want)
      if (pd==0) cout << "Null pointer on third type-cast" << endl;

// pd = dynamic_cast(pnot); //error C2683: 'dynamic_cast' : 'CNotDerived' 不是多态类型 // if (pnot==0) cout

// pd = static_cast(pnot); //错误 C2440: 'static_cast' : 无法从 'CNotDerived *' 转换为 'CDerived *' // if (pnot==0) cout

      //below lines compiled with ms vs2008 - I believe compiler SHOULD have flagged below as an error - but did not.
      pd2 = static_cast<CDerived2*>(pba); //compiles ok but obviously incorrect
      if (pd2==0) cout << "Null pointer on fourth type-cast" << endl;
      cout << pd2->b << endl;  //compiler had decided to give us CDerived->a value! Incorrect.

      pd2 = static_cast<CDerived2*>(pdx); //compiles ok 
      if (pd2==0) cout << "Null pointer on fourth type-cast" << endl;
      cout << pd2->b << endl;  //gives correct value for b (7)

      pd3 = static_cast<CDerived2*>(pdx); //error C2440: '=' : cannot convert from 'CDerived2 *' to 'CDerived3 *'
      if (pd3==0) cout << "Null pointer on fourth type-cast" << endl;
      cout << pd3->c << endl; 

  } catch (exception& e) {
      cout << "Exception: " << e.what();
  }
  return 0;
}

【问题讨论】:

    标签: c++ casting


    【解决方案1】:

    主要情况是它们具有父子关系或者都是内置数字类型。如果一个对象可以从另一个对象构造,整数类型可以转换为枚举类型,并且 void 指针可以转换为指向对象的指针,这也是有效的。

    编辑主要情况(我省略了一些更晦涩的情况,如指向成员的强制转换):

    5.2.9/2:

    表达式 e 可以使用 a 显式转换为类型 T 如果声明“T t(e);”,则为 static_cast(e) 形式的 static_cast 对于一些发明的临时变量 t (8.5) 是良构的。

    5.2.9/4:

    任何表达式都可以显式转换为“cv void”类型。这 表达式值被丢弃。

    5.2.9/5:

    “cv1 B”类型的左值,其中 B 是类类型,可以强制转换为 键入“对 cv2 D 的引用”,其中 D 是一个派生自的类(第 10 条) B、如果从“pointer to D”到“pointer to”的有效标准转换 B” 存在 (4.10),cv2 与 cvqualification 相同或更高 cvqualification than, cv1, and B不是D的虚基类。

    7.2.9/7:

    整数类型的值可以显式转换为枚举 输入。

    7.2.9/10:

    “指向 cv void 的指针”类型的右值可以显式转换为 指向对象类型的指针。

    【讨论】:

      【解决方案2】:

      “兼容类型”是指以下之一:

      1. 具有父子关系的类型
      2. 兼容的内置类型(double 到 float、int 到 bool 等)
      3. 具有定义的转换运算符到其他一些其他不相关类型的类型。例如,我可能会创建一个自定义 Fraction 类,我可以为它定义 operator double(),这将使我的类可以转换为双精度类。
      4. 一种类型可以由另一种类型构成。例如,我可以创建一个 Fraction::Fraction(double) 构造函数,这将使 double 可转换为我的类。

      【讨论】:

        【解决方案3】:

        dynamic_cast 相比,static_cast 可以对没有 vtable 的类型执行向下转换,而 dynamic_cast 不能。 static_cast 不会检查强制转换在运行时是否有效。它只是在编译时调整指针偏移量。

        兼容类型意味着

        • 本机数字类型,例如 doublelong
        • 基本类型和派生类型
        • 可以通过转换运算符转换为其他类型的类型

        【讨论】:

          【解决方案4】:

          在静态转换的情况下,完全由程序员决定转换是否会导致定义的行为或未定义的行为,而在动态转换的情况下,检查可以在运行时执行。

          因此,静态转换和动态转换的唯一区别是静态转换不需要动态转换的运行时开销。

          【讨论】:

            【解决方案5】:

            除了基-派生-基转换之外,static_cast 还可以在两种类型之间存在隐式或显式转换时使用。

            隐式类型转换示例:

            // From int to double
            int i = 0;
            double d = i;
            
            class Integer
            {
            public:
                Integer(int value)
                :   value_(value)
                {
                    // ...
                }
            
            private:
                int value_;
            };
            
            // From int to Integer
            int a = 0;
            Integer b = a;
            

            显式类型转换示例:

            // From double to int
            double d = 0.0;
            int i = static_cast<int>(d);
            
            class Integer
            {
            public:
                explicit Integer(int value)
                :   value_(value)
                {
                    // ...
                }
            
            private:
                int value_;
            };
            
            // From int to Integer
            int a = 0;
            Integer b(a);
            Integer c = static_cast<Integer>(a);
            

            见:Type Casting

            【讨论】:

              【解决方案6】:
              void foo( base *bPtr )
              {
                   derived *dPtr = static_cast< derived*> (bPtr) ; 
                       // Safe as long as the bPtr has the derived class sub object too.
                       // But what if bPtr is just pointing to a base* ?
              }
              
              derived* objOne = new derived() ;
              foo( objOne ) ; // safe
              
              base* obj = new base() ;
              foo( obj ) ; // unsafe
              

              在函数中,不检查类型兼容性,返回derived*

              演示:http://ideone.com/YwHJn

              【讨论】:

              • 这不是问题的答案
              • @Andy T :可能,我误解了。谢谢:)
              • 这不是我的“-1”,最好删除答案以避免其他反对意见
              • 这是一个很好的例子,但我已经明白了。我在问兼容性是什么意思。
              猜你喜欢
              • 2017-07-11
              • 1970-01-01
              • 2011-07-19
              • 2018-09-11
              • 2020-05-30
              • 2013-07-01
              • 1970-01-01
              • 2015-08-09
              • 1970-01-01
              相关资源
              最近更新 更多