C/C++类型转换

时间:2024-10-16 14:50:40

C语言中的类型转换

#include<stdio.h>
void Insert(size_t pos){
  // int被转换为size_t,当传入的pos = 0时,会陷入死循环
  int end = 10;
  // 比较的时候end会隐式类型转换成size_t,再比较
  while (end >= pos){
    cout << end << "挪走" << endl;
    --end;
  }
}//数组索引最好使用size_t,因为它是非负的(无符号的)end从10开始变为-1后就被size_t视为一个很大的数了,然后进入函数体中还会继续减
int main(){
  //1.溢出了
  long val = 4566666666666661111113LL;
  int ret = (int)val;
  printf("%d\n", ret); // int 的取值范围是 -2,147,483,648 到 2,147,483,647。long val超出了int的范围。

  //2.数据丢失精度
  int i = 1233456789;
  float j = i;
  double jj = i;
  printf("%f\n", j); // 1233456768.000000这与float底层存储精度有关
  printf("%lf\n", jj); // 1233456789.000000 double就没有这个问题

  //3.藏在背后的隐式类型转换导致意外的结果,如上insert函数
  Insert(0);

  return 0;
}

C++类型转换

class A{
  private:
    int a = 1, b = 1;
  public:
    A() { cout << "A()" << endl; }
    ~A() { cout << "~A()" << endl; }
    operator int(){
      cout << "operator int()" << endl;
      return a + b;
    }
};
class AA{
};
class BB:public AA{
};
class CC{
  public:
  virtual void f(){}
  int _a;
};
class DD:public CC{
  public:
  int _b;
};
void test_dynamic_cast(CC* p){
  DD *pp = dynamic_cast<DD *>(p);
  if(pp==nullptr){
    cout << "dynamic_cast failed\n";
  }
  else{
    cout << pp->_a << endl
         << pp->_b << endl;
  }
}


int main()
{

  //1.C++中使用单参的构造函数来进行类型转换
  string s = "123456";//将C风格的字符数组转换为string对象,这是string的构造函数保证的
  // 等价于string s("1233465");
  // 这种方式是 C++ 对于字符串处理的一种常见做法,能够有效地避免 C 风格字符串的一些常见问题,如内存管理和缓冲区溢出。

  //2.重载
  A obj;
  int l = obj;//这一句就是一个A类对象可以转为int
  cout << l << endl;
  int m = (int)obj;
  cout << m << endl;
  //A() operator int() 2 operator int() 2 ~A()

  // C++依然兼容C语言的两种类型转换方式,但是为了加强类型转换时的可视性,C++引入了四种类型转换操作符,它们是一些进行类型转换时的命名建议,并不强制
  //3.static_cast<>():有关联的类型之间进行转换
  double d = 3.14;
  int i = static_cast<int> (d);//静态转换
  cout << i << endl;//3

  //4.reinterpret_cast<>():强转
  int a = 12;
  int *p = reinterpret_cast<int *>(a);

  //5.const_cast<>():删除const属性

  const int n = 10;
  int *p2 = const_cast<int *>(&n);
  *p2 = 20;
  cout << *p2 << endl;//20
  cout << n << endl;//10//const的变量编译器知道无法修改,编译器直接在编译阶段就将10直接与使用n的地方联系起来了。所以其实n在内存中已经改了
  // 如果是volatile const int n = 10;cout<<n<<endl;就是20。因为volatile要求编译器不要搞你那优化了,从内存去读取吧;


  //6.赋值兼容
  BB obj2;
  AA obj1;
  obj1 = obj2; // 子类对象赋值给父类对象

  AA *pp = &obj2; // 子类地址赋给父类指针
  BB &ref = obj2;
  AA &reff = ref;//子类引用赋给父类引用

  //父类指针现在指向子类,这是安全的;反之不安全。这主要是因为子类是在父类的扩展,空间和功能都扩展了
  //为了解决这一问题,有了dynamic_cast<>():如果可以转换成功,就转换,反之返回nullptr
  cout << "___________" << endl;
  CC objC;
  test_dynamic_cast(&objC);
}