c#开发数据格式转换小程序_C开发人员的C ++类型转换

c#开发数据格式转换小程序

类型转换是使C ++具有更多类型安全性,更强大的功能,并且可以说服您在C上使用它。但是,当您是新手或从C背景移居时,这也是一个被低估的主题。 因此,我想出了一篇关于它的文章。 在这里,我们不仅会看到带有C开发人员示例的C ++类型转换,而且还将介绍为什么我们需要类型转换? & C ++类型的铸造作弊代码,C开发人员可以轻松记住和使用它。

尽管我不是专家,但是到目前为止,这是我从各种来源和5年以上的行业经验中学到的。

在C ++中,有5种不同类型的强制类型转换:C样式强制类型转换,static_cast,const_cast,dynamic_cast和reinterpret_cast。

我通常从“我们为什么需要它?”开始,但是这一次我们首先快速地讲一些术语,而我将以一些有关类型转换的CPP核心指南结束本文。

您需要面对的行话

  1. 隐式转换:编译器在其中自动进行类型转换。 像float f = 3;一样,这里的编译器不会抱怨,而是直接将整数类型3转换为float并赋给f。
  2. 显式转换 :开发人员使用强制转换运算符指导转换。 所有类型的手动转换都属于显式类型转换类别。 像int * p =(int *)std :: malloc(10);,这里我们显式将void *强制转换为int *。
  3. l-value :代表内存位置的标识符。 例如,变量名,* ptr(ptr指向内存位置等)。
  4. r值 :不是l值的值,r值出现在赋值(=)运算符的右侧。 喜欢
int a = 5 ; // 5 = r-value, 
q = p + 5 ; // p + 5 is r-value

注意:尽管在C ++中有一些例外和更多内容需要学习lvalue,rvalue及其引用 。

为什么我们需要类型转换?

  • 数据表示内存中的位(0和1)。
  • 数据类型是编译器指令,它告诉编译器如何存储和处理特定数据。uint32_t a = 5; 通过此语句,您可以假定将在内存中保留4个字节,并在执行时将在该内存位置存储0000 0000 0000 0000 0000 0000 0000 0000 0101数据位。 这很简单。
  • 让我们再进一步一点,浮点数f = 3.0; 该语句还将在内存中保留4个字节并以1)的形式存储数据位。 符号位2)。 指数&3)。 尾数。 回想一下如何将浮点数存储在memory中 。
  • 但是,当您编写类似float f = 3;的代码时,编译器会困惑于如何在float类型的内存中存储整数值。
  • 因此,它会自动假定(此处为隐式转换 )要存储3.0而不是3,从人的角度来看这在技术上是相同的,但是从计算机内存角度考虑导致它们存储不同的情况则有所不同。
  • 在许多这样的方案中,您提供了要存储在内存中的数据,这些数据用来表示不同的数据类型。
  • 例如,在下面的示例中,您尝试将类型B的对象分配给类型A的对象
class A { };
class B { };
int main ()
 {
  B b;
  A a = b; 
  return 0 ;
}
  • 在这种情况下,编译器无法假定任何内容,只会引发编译错误:
exit status 1
error: no viable conversion from 'B' to 'A'
  A a = b;
    ^   ~
note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'B' to ' const A &' for 1st argument
class A {};
      ^
note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'B' to 'A &&' for 1st argument
class A {};
      ^
1 error generated.
  • 但是,当您按以下方式定义转换运算符时:
class B {
public :
  operator A () {
    cout << "CONVERSION OPERATOR\n" ;
    return A();
  } 
};
  • 编译器将仅调用此成员函数,并且不会引发任何错误,因为程序员明确提到这就是他/她想要转换的方式。

5种C ++类型转换以及C开发人员示例

1️C型演员表

int main ()  { 
    float res = 10 / 4 ;
    cout <
  • 当您尝试运行上面的代码时,您会得到2作为我们没有想到的输出。 为了正确初始化res变量,我们需要使用float进行类型转换,如下所示:
float res = ( float ) 10 / 4 ;
  • 现在您的答案将是2.5。 这种类型的铸造看起来非常简单直接。
  • 您还可以在C ++中使用以下形式编写:
float res = float ( 10 ) / 4 ;
  • C样式强制转换可以更改数据类型,而无需更改基础内存表示,这可能会导致垃圾结果。

2️ static_cast

  • 如果您是像我这样的C开发人员,那么这将是您最好的goto C ++ cast,它适合大多数示例,例如:
int * p = std :: malloc ( 10 );
  • 当您尝试使用C编译器编译以上代码时,它可以正常工作。 但是C ++编译器还不够好。 它将引发如下错误:
exit status 1
error: cannot initialize a variable of type 'int *' with an rvalue of type 'void *'
  int * p = std :: malloc ( 10 );
        ^   ~~~~~~~~~~
1 error generated.
  • 首先想到的是C样式的强制转换:
int * p = ( int *) std :: malloc ( 10 );
  • 这将起作用,但是在C ++中不建议使用这种样式的转换。 static_cast会像这样处理隐式转换。 我们将主要使用它在隐式转换失败的地方进行转换,例如std :: malloc。
int * p = static_cast < int *>( std :: malloc ( 10 ));
  • static_cast的主要优点在于,它提供了编译时类型检查,这使得更容易出错。 让我们用C ++示例来了解这一点:
class B { };
class D : public B {};
class X { };

int main ()
 {
  D* d = new D;
  B* b = static_cast (d); // this works
  X* x = static_cast (d); // ERROR - Won't compile
  return 0 ;
}
  • 如您所见,在不了解所有涉及的所有类的情况下,没有简单的方法来区分这两种情况。
  • C样式转换的另一个问题是很难定位。 在复杂的表达式中,很难看到C样式的强制转换,例如T(something)语法等效于(T)something。

3️ const_cast

  • 现在,我们将直接跳至示例。 没有理论可以比例子更好地解释这一点。

1.忽略常数

int i = 0 ;
const int & ref = i;
const int * ptr = &i;

*ptr = 3 ; // Not OK
const_cast < int &>(ref) = 3 ;  //OK
* const_cast < int *>(ptr) = 3 ; //OK
  • 由于被分配给对象(此处为i)不是const,因此您可以修改i。 如果将const限定符添加到i,代码将进行编译,但是其行为将是不确定的(这意味着从“工作得很好”到“程序将崩溃>”。)

2.使用const this指针修改数据成员

  • const_cast可以通过将指针声明为const的方法来更改非const类成员。 -当基于const重载成员函数时,这也很有用,例如:
class X
{
public :
    int var;
    void changeAndPrint ( int temp) const
     {
        this ->var = temp;                    // Throw compilation error
        ( const_cast ( this ))->var = temp; // Works fine
    }
    void changeAndPrint ( int *temp)
     {
        // Do some stuff
    }
};

int main ()
 {
    int a = 4 ;
    X x;
    x.changeAndPrint(&a);
    x.changeAndPrint( 5 );
    cout << x.var << endl ;
    return 0 ;
}

3.将const参数传递给仅接受非const参数的函数

  • const_cast也可以用于将const数据传递给不接收const参数的函数。 请参见以下代码:
int fun ( int * ptr) 
 { 
    return (*ptr + 10 ); 
} 

int main ( void ) 
 { 
    const int val = 10 ; 
    cout << fun( const_cast < int *>(&val)); 
    return 0 ; 
} 

4.被抛弃的挥发性属性

  • const_cast也可以用于丢弃volatile属性。 上面我们在const_cast中讨论的内容对于volatile关键字也有效。

4️ dynamic_cast

  • dynamic_cast在运行时使用类型检查,而static_cast则在编译时使用类型检查。 当您不知道它代表的输入类型时,dynamic_cast更为有用。 假设:
Base* CreateRandom ()
 {
    if ( (rand()% 2 ) == 0 )
        return new Derived1;
    else
        return new Derived2;
}

Base* base = CreateRandom();
  • 如您所见,我们不知道CreateRandom()在运行时将返回哪个对象,但是如果它返回Derived1,则要执行Derived1的Method1()。 因此,在这种情况下,您可以按以下方式使用dynamic_cast
Derived1 *pD1 =dynamic_cast (base);
if (pD1){
    pD1->Method1();
}
  • 如果dynamic_cast的输入未指向有效数据,则它将为指针返回nullptr或为引用抛出std :: bad_cast异常。 为了使用dynamic_cast,您的类必须为多态类型,即必须至少包含一个虚拟方法。
  • dynamic_cast利用RTTI( 运行时类型标识 )机制。

5️ reinterpret_cast

  • reinterpret_cast是一个编译器指令,它告诉编译器将当前类型视为新类型。
  • 您可以使用reinterpret_cast将任何指针或整数类型转换为任何其他指针或整数类型。
  • 这可能会导致危险的情况:什么都不会阻止您将int转换为std :: string *。
  • 您将在嵌入式系统中使用reinterpret_cast。 适用于reinterpret_cast的常见情况是在uintptr_t和实际指针之间或在以下两者之间进行转换:
error:static_cast from 'int *' to 'uintptr_t'
      (aka 'unsigned long' ) is not allowed
        uintptr_t ptr = static_cast < uintptr_t >(p);
                        ^~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
  • 而是使用以下命令:
uintptr_t ptr = reinterpret_cast < uintptr_t >(p);
  • 我尝试涵盖了大多数复杂性,以清除不同类型转换背后的主要概念,但是,仍然有可能我会错过一些。 因此,这就是C ++类型转换的例子,并为C开发人员提供了一个示例。 让我们快速回顾一下:

供C开发人员在类型转换时使用C ++的备忘代码

阅读完所有这些内容后,您可能会混淆使用什么以及何时使用! 这就是为什么我创建了这个作弊代码

  • 避免使用C样式强制转换。
  • 投放时请确定要什么。
  • 无论您使用的是C型转换,都应使用static_cast。
  • 对多态类使用dynamic_cast。 请记住,仅对继承层次结构中具有至少一个虚拟成员的类使用dynamic_cast。
  • 需要删除constvolatile限定符时,请使用const_cast
  • 如果没有选择,请使用reinterpret_cast。

注意:通常应避免使用const_castreinterpret_cast因为如果使用不正确,它们可能会有害。 除非您有充分的理由使用它们,否则不要使用它。

一些C ++核心准则

  • P.4:理想情况下,程序应为静态(编译时)类型安全
  • ES.48:避免强制转换
  • ES.49:如果必须使用演员表,请使用命名的演员表 ES.50:不要放弃 const
  • C.146: 在无法避免类层次结构导航的地方 使用 dynamic_cast
  • C.147: 当未能找到所需的类被视为错误时, 请 对引用类型 使用 dynamic_cast
  • C.148: 当无法找到所需的类被认为是有效的替代方法时, 使用 dynamic_cast 指向指针类型

翻译自: https://hackernoon.com/c-type-casting-for-c-developers-0c823y9k

c#开发数据格式转换小程序

你可能感兴趣的:(c++,指针,python,java,编程语言)