C++几个常用类型转换

static_cast <new_type> (expression) 静态转换

 

静态转换是最接近于C风格转换,很多时候都需要程序员自身去判断转换是否安全。比如:

double d=3.14159265;

int i = static_cast<int>(d);

 

但static_cast已经有安全性的考虑了,比如对于不相关类指针之间的转换。参见下面的例子:

复制代码
 1 // class type-casting
 2 #include <iostream>
 3 using namespace std;
 4 
 5 class CDummy {
 6     float i,j;
 7 };
 8 
 9 class CAddition {
10     int x,y;
11   public:
12     CAddition (int a, int b) { x=a; y=b; }
13     int result() { return x+y;}
14 };
15 
16 int main () {
17   CDummy d;
18   CAddition * padd;
19   padd = (CAddition*) &d;
20   cout << padd->result();
21   return 0;
22 }
复制代码

这个例子与之前举的例子很像,只是CAddition与CDummy类没有任何关系了,但main()中C风格的转换仍是允许的padd = (CAddition*) &d,这样的转换没有安全性可言。

 

如果在main()中使用static_cast,像这样:

复制代码
1  int main () {
2    CDummy d;
3    CAddition * padd;
4    padd = static_cast<CAddition*> (&d);
5    cout << padd->result();
6    return 0;
7 }
复制代码

 

编译器就能看到这种不相关类指针转换的不安全,报出如下图所示的错误:

注意这时不是以warning形式给出的,而直接是不可通过编译的error。从提示信息里可以看到,编译器说如果需要这种强制转换,要使用reinterpret_cast(稍候会说)或者C风格的两种转换。

总结一下:static_cast最接近于C风格转换了,但在无关类的类指针之间转换上,有安全性的提升。

 

dynamic_cast <new_type> (expression) 动态转换

 

动态转换确保类指针的转换是合适完整的,它有两个重要的约束条件,其一是要求new_type为指针或引用,其二是下行转换时要求基类是多态的(基类中包含至少一个虚函数)。

看一下下面的例子:

复制代码
 1 #include <iostream>
 2 using namespace std;
 3 class CBase { };
 4 class CDerived: public CBase { };
 5 
 6 int main()
 7 {
 8 CBase b; CBase* pb;
 9 CDerived d; CDerived* pd;
10 
11 pb = dynamic_cast<CBase*>(&d);     // ok: derived-to-base
12 pd = dynamic_cast<CDerived*>(&b);  // wrong: base-to-derived 
13 }
复制代码

在最后一行代码有问题,编译器给的错误提示如下图所示:

把类的定义改成:

class CBase { virtual void dummy() {} };

class CDerived: public CBase {};

再编译,结果如下图所示:

编译都可以顺利通过了。这里我们在main函数的最后添加两句话:

cout << pb << endl;

cout << pd << endl;

输出pb和pd的指针值,结果如下:

我们看到一个奇怪的现象,将父类经过dynamic_cast转成子类的指针竟然是空指针!这正是dynamic_cast提升安全性的功能,dynamic_cast可以识别出不安全的下行转换,但并不抛出异常,而是将转换的结果设置成null(空指针)。

再举一个例子:

复制代码
 1 #include <iostream>
 2 #include <exception>
 3 using namespace std;
 4 
 5 class CBase { virtual void dummy() {} };
 6 class CDerived: public CBase { int a; };
 7 
 8 int main () {
 9   try {
10     CBase * pba = new CDerived;
11     CBase * pbb = new CBase;
12     CDerived * pd;
13 
14     pd = dynamic_cast<CDerived*>(pba);
15     if (pd==0) cout << "Null pointer on first type-cast" << endl;
16 
17     pd = dynamic_cast<CDerived*>(pbb);
18     if (pd==0) cout << "Null pointer on second type-cast" << endl;
19 
20   } catch (exception& e) {cout << "Exception: " << e.what();}
21   return 0;
22 }
复制代码

输出结果是:Null pointer on second type-cast

两个dynamic_cast都是下行转换,第一个转换是安全的,因为指向对象的本质是子类,转换的结果使子类指针指向子类,天经地义;第二个转换是不安全的,因为指向对象的本质是父类,“指鹿为马”或指向不存在的空间很可能发生!

最后补充一个特殊情况,当待转换指针是void*或者转换目标指针是void*时,dynamic_cast总是认为是安全的,举个例子:

复制代码
 1 #include <iostream>
 2 using namespace std;
 3 class A {virtual void f(){}};
 4 class B {virtual void f(){}};
 5 
 6 int main() {
 7     A* pa = new A;
 8     B* pb = new B;
 9     void* pv = dynamic_cast<void*>(pa);
10     cout << pv << endl;
11     // pv now points to an object of type A
12 
13     pv = dynamic_cast<void*>(pb);
14     cout << pv << endl;
15     // pv now points to an object of type B
16 }
复制代码

运行结果如下:

可见dynamic_cast认为空指针的转换安全的,但这里类A和类B必须是多态的,包含虚函数,若不是,则会编译报错。

 

reinterpret_cast <new_type> (expression) 重解释转换

 

这个转换是最“不安全”的,两个没有任何关系的类指针之间转换都可以用这个转换实现,举个例子:

class A {};

class B {};

A * a = new A;

B * b = reinterpret_cast<B*>(a);//correct!

更厉害的是,reinterpret_cast可以把整型数转换成地址(指针),这种转换在系统底层的操作,有极强的平台依赖性,移植性不好。

它同样要求new_type是指针或引用,下面的例子是通不过编译的:

double a=2000.3;

short b;

b = reinterpret_cast<short> (a); //compile error!

 

const_cast <new_type> (expression) 常量向非常量转换

这个转换好理解,可以将常量转成非常量。

复制代码
 1 // const_cast
 2 #include <iostream>
 3 using namespace std;
 4 
 5 void print (char * str)
 6 {
 7   cout << str << endl;
 8 }
 9 
10 int main () {
11   const char * c = "sample text";
12   char *cc = const_cast<char *> (c) ;
13   Print(cc);
14   return 0;
15 }
复制代码

char *cc = const_cast<char *>(c)可以看出了这个转换的作用了,但切记,这个转换并不转换原常量本身,即c还是常量,只是它返回的结果cc是非常量了

 

 

总结

C风格转换是“万能的转换”,但需要程序员把握转换的安全性,编译器无能为力;static_cast最接近于C风格转换,但在无关类指针转换时,编译器会报错,提升了安全性;dynamic_cast要求转换类型必须是指针或引用,且在下行转换时要求基类是多态的,如果发现下行转换不安全,dynamic_cast返回一个null指针,dynamic_cast总是认为void*之间的转换是安全的;reinterpret_cast可以对无关类指针进行转换,甚至可以直接将整型值转成指针,这种转换是底层的,有较强的平台依赖性,可移植性差;const_cast可以将常量转成非常量,但不会破坏原常量的const属性,只是返回一个去掉const的变量。

注:本文中大部分样例来源自C++标准网站:

http://www.cplusplus.com/doc/tutorial/typecasting/ 

以及微软的MSDN:

http://msdn.microsoft.com/en-us/library/cby9kycs

若有理解出错的地方,望不吝指正。


转自:http://www.cnblogs.com/jerry19880126/archive/2012/08/14/2638192.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: UTM(Universal Transverse Mercator,通用横轴墨卡托投影)是地理坐标系统的一种投影方式,它将地球表面的经纬度坐标转换成平面笛卡尔坐标系,常用于地图绘制和测量工作。下面是一段用C语言编写的UTM转换的源代码。 ```c #include <stdio.h> #define PI 3.14159265 // 计算弧度 double toRadians(double degree) { return degree * PI / 180.0; } // 计算UTM转换参数 void toUTM(double latitude, double longitude, int* zone, double* easting, double* northing) { double a = 6378137.0; // 地球长半轴 double k0 = 0.9996; // 横向缩放比例 double falseEasting = 500000.0; // 假东坐标 double falseNorthing = 0.0; // 假北坐标 double longitudeOrigin = (*zone - 1) * 6 - 180 + 3.0; // 中央子午线经度 // 转换经纬度为弧度 double latRad = toRadians(latitude); double lonRad = toRadians(longitude); double lonOriginRad = toRadians(longitudeOrigin); double eccSquared = 0.00669438; // 椭球体偏心率的平方 double N = a / sqrt(1 - eccSquared * sin(latRad) * sin(latRad)); double T = tan(latRad) * tan(latRad); double C = eccSquared * cos(latRad) * cos(latRad); double A = cos(latRad) * (lonRad - lonOriginRad); double M = a * ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256) * latRad - (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 + 45 * eccSquared * eccSquared * eccSquared / 1024) * sin(2 * latRad) + (15 * eccSquared * eccSquared / 256 + 45 * eccSquared * eccSquared * eccSquared / 1024) * sin(4 * latRad) - (35 * eccSquared * eccSquared * eccSquared / 3072) * sin(6 * latRad)); *easting = k0 * N * (A + (1 - T + C) * (A * A * A) / 6 + (5 - 18 * T + T * T + 72 * C - 58 * eccSquared) * (A * A * A * A * A) / 120) + falseEasting; *northing = k0 * (M + N * tan(latRad) * ((A * A) / 2 + (5 - T + 9 * C + 4 * C * C) * (A * A * A * A) / 24 + (61 - 58 * T + T * T + 600 * C - 330 * eccSquared) * (A * A * A * A * A * A) / 720)) + falseNorthing; } int main() { double latitude = 40.7128; // 纬度 double longitude = -74.0060; // 经度 int zone; double easting, northing; zone = (int)(longitude + 180) / 6 + 1; // 计算UTM区域 toUTM(latitude, longitude, &zone, &easting, &northing); printf("UTM Zone: %d\n", zone); printf("Easting: %.2f\n", easting); printf("Northing: %.2f\n", northing); return 0; } ``` 以上是UTM转换的源码示例,通过调用`toUTM`函数可以将给定的纬度和经度转换为UTM投影坐标系下的东坐标和北坐标。在示例代码中,给定了纽约市的纬度和经度,程序会根据计算得到的UTM区域和转换参数,打印出对应的UTM坐标信息。 ### 回答2: UTM(通用转换方法)是一种用于将地理坐标(经度和纬度)转换为平面坐标(东北坐标)的方法。在编写UTM转换源码C时,需要先了解UTM转换的原理和计算公式。 UTM转换可以分为两个主要步骤:第一步是确定所在的UTM坐标带,即确定经度所在的6度带。第二步是根据公式将经度和纬度转换为平面坐标。 在编写源码时,需要考虑以下几个关键点: 1. 首先,需要用到一些数学函数库,如三角函数库,来进行相关的计算。可以使用C语言提供的math.h库来调用这些函数。 2. 其次,需要编写一个函数,使其接收经度和纬度作为输入,并返回相应的UTM平面坐标。这个函数需要按照UTM转换的公式进行计算,并将结果返回。 3. 在进行计算时,还需要考虑大地基准面、误差校正等因素,以确保转换的准确性。 4. 最后,需要对源码进行测试,以确保其在各种情况下的转换结果是正确的。可以使用已知的地理坐标和相应的UTM平面坐标进行比对,以验证转换结果的准确性。 总之,编写UTM转换的源码需要理解UTM转换的原理和公式,并结合C语言的数学库和函数来实现转换。在编写和测试时,需要注意参数的传递、计算的准确性以及结果的验证。这样才能确保源码的功能和准确性。 ### 回答3: utm转换是一种将经纬度坐标转换为地理标识码的过程。在C语言中,我们可以使用一些库和算法来实现utm转换。 utm转换通常涉及到以下几个方面的计算:地球椭球体模型、大地坐标系和投影坐标系之间的换算,以及经度纬度转换为区域、带号和坐标的关系。 首先,我们需要引入一些数学库,例如sin、cos和tan等,这些库提供了一些常用的数学函数,可以帮助我们进行复杂的计算。然后,我们可以根据大地坐标系和投影坐标系之间的转换公式,编写相应的代码。 在进行utm转换时,我们需要知道源代码中的输入数据格式,即经纬度数据的表示方法,例如度分秒制还是度制。然后,我们可以通过读取用户输入的经纬度数据,并进行格式化处理,并将其转换为弧度表示形式,以便后续计算。 在计算过程中,需要根据所在的经度区间,确定utm的带号。然后,根据带号,可以推算出对应的投影中央子午线的经度。接下来,我们可以根据相关公式,计算出经纬度的投影坐标。 最后,我们可以将计算得到的utm坐标输出到控制台或保存到文件中,以供后续使用。 需要注意的是,utm转换是一种复杂的计算过程,需要嵌入大量的数学知识和计算公式。因此,我们可以采用现有的utm转换库来简化开发过程,并提高准确性和效率。 以上是用300字中文回答utm转换源码C的一种方式,当然具体实现还需要根据具体需求和环境进行进一步的调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值