C++11新特性(3)

1.类型强制转换

  • static_cast,interpret_cast,const_cast和dynamic_cast
  • static_cast
    static_cast用来进行比较“自然”和低风险的转换,比如整形和实数型、字符型之间互相转换。
    static_cast不能用来在不同类型的指针之间互相转换,也不能用于整型和指针之间的互相转换,也不能用于不同类型的引用之间的转换。
#include <iostream>
using namespace std;
class A
{
public:
    operator int() { return 1; }
    operator char * () { return NULL; }
};
int main()
{
    A a;
    int n; char * p = "New Dragon Inn";
    n = static_cast<int>(3.14); // n 的值变为 3
    n = static_cast<int>(a); //调用a.operator int, n的值变为 1
    p = static_cast<char*>(a);
    //调用a.operator int *,p的值变为 NULL
    n = static_cast<int> (p);
    //编译错误, static_cast不能将指针转换成整型
    p = static_cast<char*>(n);
    //编译错误, static_cast不能将整型转换成指针
    return 0;
}
  • reinterpret_cast
    reinterpret_cast用来进行各种不同类型的指针之间的转换、不同类型的引用之间转换,以及指针和能容纳得下指针的整数类型之间的转换。转换的时候,执行的是逐个比特拷贝的操作。
#include <iostream>
using namespace std;
class A
{
public:
    int i;
    int j;
    A(int n) :i(n), j(n) { }
};
int main()
{
    A a(100);
    int & r = reinterpret_cast<int&>(a); //强行让 r 引用 a
    r = 200; //把 a.i 变成了 200
    cout << a.i << "," << a.j << endl; // 输出 200,100
    int n = 300;
    A * pa = reinterpret_cast<A*> (&n); //强行让 pa 指向 n
    pa->i = 400; // n 变成 400
    pa->j = 500; //此条语句不安全,很可能导致程序崩溃
    cout << n << endl; // 输出 400
    long long la = 0x12345678abcdLL;
    pa = reinterpret_cast<A*>(la);
    // la太长,只取低32位0x5678abcd拷贝给pa
    unsigned int u = reinterpret_cast<unsigned int>(pa);
    //pa逐个比特拷贝到u
    cout << hex << u << endl; //输出 5678abcd
    typedef void(*PF1) (int);
    typedef int(*PF2) (int, char *);
    PF1 pf1; PF2 pf2;
    pf2 = reinterpret_cast<PF2>(pf1);
    //两个不同类型的函数指针之间可以互相转换
}
  • const_cast
    用来去除const属性的转换。将const引用转换成同类型的非const引用,将const指针转换为同类型的非const指针时用它。
const string s = “Inception”;
string & p = const_cast<string&>(s);
string * ps = const_cast<string*>(&s);
// &s的类型是const string *
  • dynamic_cast
    dynamic_cast专门用于将多态基类的指针或引用,强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果返回NULL指针。
    dynamic_cast不能用于将非多态基类的指针或引用,
    强制转换为派生类的指针或引用.
#include <iostream>
#include <string>
using namespace std;
class Base
{ //有虚函数,因此是多态基类
public:
    virtual ~Base() { }
};
class Derived :public Base { };
int main()
{
    Base b;
    Derived d;
    Derived * pd;
    pd = reinterpret_cast<Derived*> (&b);
    if (pd == NULL)
        //此处pd不会为NULL。 reinterpret_cast不检查安全性,总是进行转换
        cout << "unsafe reinterpret_cast" << endl; //不会执行
    pd = dynamic_cast<Derived*> (&b);
    if (pd == NULL)
        //结果会是NULL,因为 &b不是指向派生类对象,此转换不安全
        cout << "unsafe dynamic_cast1" << endl; //会执行
    pd = dynamic_cast<Derived*> (&d); //安全的转换
    if (pd == NULL) //此处pd 不会为NULL
        cout << "unsafe dynamic_cast2" << endl; //不会执行
    return 0;
}

2.异常处理

  • 程序运行中难免发生错误
    数组元素的下标超界、访问NULL指针
    除数为0
    动态内存分配new需要的存储空间太大
  • 引起原因
    代码质量低
    输入数据不符合要求
    程序的算法设计时考虑不周到
  • 用try、catch进行异常处理
#include <iostream>
using namespace std;
int main()
{
    double m, n;
    cin >> m >> n;
    try {
        cout << "before dividing." << endl;
        if (n == 0)
            throw - 1; //抛出int类型异常
        else
            cout << m / n << endl;
        cout << "after dividing." << endl;
    }
    catch (double d) {
        cout << "catch(double) " << d << endl;
    }
    catch (int e) {
        cout << "catch(int) " << e << endl;
    }
    cout << "finished" << endl;
    return 0;
}
/*
程序运行结果如下:
9 6↙
before dividing.
1.5
after dividing.
finished
*/
  • 捕获任何异常的catch块
#include <iostream>
using namespace std;
int main()
{
    double m, n;
    cin >> m >> n;
    try {
        cout << "before dividing." << endl;
        if (n == 0)
            throw - 1; //抛出整型异常
        else if (m == 0)
            throw - 1.0; //抛出double型异常
        else
            cout << m / n << endl;
        cout << "after dividing." << endl;
    }
    catch (double d) {
        cout << "catch(double) " << d << endl;
    }
    catch (...) {
        cout << "catch(...) " << endl;
    }
    cout << "finished" << endl;
    return 0;
}
/*
程序运行结果:
9 0↙                                         0 6↙
before dividing.                         before dividing.
catch(...)                                   catch(double) -1
finished                                     finished
注意: try块中定义的局部对象,发生异常时会析构!
*/
  • 异常的再抛出
    如果一个函数在执行的过程中,抛出的异常在本函数内就被catch块捕获并处理了,那么该异常就不会抛给这个函数的调用者(也称“上一层的函数” );如果异常在本函数中没被处理,就会被抛给上一层的函数。
#include <iostream>
#include <string>
using namespace std;
class CException
{
public:
    string msg;
    CException(string s) :msg(s) { }
};
double Devide(double x, double y)
{
    if (y == 0)
        throw CException("devided by zero");
    cout << "in Devide" << endl;
    return x / y;
}
int CountTax(int salary)
{
    try {
        if (salary < 0)
            throw - 1;
        cout << "counting tax" << endl;
    }
    catch (int) {
        cout << "salary < 0" << endl;
    }
    cout << "tax counted" << endl;
    return salary * 0.15;
}
int main()
{
    double f = 1.2;
    try {
        CountTax(-1);
        f = Devide(3, 0);
        cout << "end of try block" << endl;
    }
    catch (CException e) {
        cout << e.msg << endl;
    }
    cout << "f=" << f << endl;
    cout << "finished" << endl;
    return 0;
}
/*
输出结果:
salary < 0
tax counted
devided by zero
f=1.2
finished
*/

3.运行时类型检查

C++运算符typeid是单目运算符,可以在程序运行过程中获取一个表达式的值的类型。 typeid运算的返回值是一type_info类的对象,里面包含了类型的信息。

#include <iostream>
#include <typeinfo> //要使用typeinfo,需要此头文件
using namespace std;
struct Base { }; //非多态基类
struct Derived : Base { };
struct Poly_Base { virtual void Func() { } }; //多态基类
struct Poly_Derived : Poly_Base { };
int main()
{
    //基本类型
    long i; int * p = NULL;
    cout << "1) int is: " << typeid(int).name() << endl;
    //输出 1) int is: int
    cout << "2) i is: " << typeid(i).name() << endl;
    //输出 2) i is: long
    cout << "3) p is: " << typeid(p).name() << endl;
    //输出 3) p is: int *
    cout << "4) *p is: " << typeid(*p).name() << endl;
    //输出 4) *p is: int
    //非多态类型
    Derived derived;
    Base* pbase = &derived;
    cout << "5) derived is: " << typeid(derived).name() << endl;
    //输出 5) derived is: struct Derived
    cout << "6) *pbase is: " << typeid(*pbase).name() << endl;
    //输出 6) *pbase is: struct Base
    cout << "7) " << (typeid(derived) == typeid(*pbase)) << endl;
    //输出 7) 0
    //多态类型
    Poly_Derived polyderived;
    Poly_Base* ppolybase = &polyderived;
    cout << "8) polyderived is: " << typeid(polyderived).name() << endl;
    //输出 8) polyderived is: struct Poly_Derived
    cout << "9) *ppolybase is: " << typeid(*ppolybase).name() << endl;
    //输出 9) *ppolybase is: struct Poly_Derived
    cout << "10) " << (typeid(polyderived) != typeid(*ppolybase)) << endl;
    //输出 10) 0
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342