C++中的强制类型转换

相信熟悉C语言与C++的人都有这样的感觉C++的语法检测比C语言要严格的多,下面是C++在
类型转换时做出的改进,有四个关键词,下面我会和大家一起来研究它们的用法,讲解我会通过注释的方法展现。



//首先我们来看c 中的类型转换
int i=10;//相似类型可以发生隐式转换
double d=i;


int  *p=&i;//非相似类型,不可以发生隐式类型转换,需要改成如下
int  j=p;


int  *p=&i;//强制类型的转换
int  j=(int)p;

const  int *p1=p;//const 与 非const之间的转换
int*  p2=(int*)p1;


//下面我们来看看C++之中的类型转换
//把隐式类型转化的情况通过四个关于类型转换的关键字来规范,防止发生数据的丢失
//关键字1:static_cast用于非状态类型的转换(静态转换),不可用在不相似类型的转换
//相当于c语言中的.隐式类型转换
int i=10;
double d=static_cast<double>(i);




//关键字2;reinterpret_cast用于非相似类型之间的转换,(有时会做出很bug的事)
int  *p=&i;
int  j=reinterpret_cast<int>(p);



//关键字3:const_cast去const 属性
const  int*  p1=p;
int *p2=const_cast<int *>(p1); 



注:void Test()
{
    const  int a=10;
    cout<<a<<endl;
    int*  p=const_cast<int*>(&a);
    *p=20;
    cout<<*p<<endl;
    cout<<a<<endl;
}

//大家运行以后可以发现输出的是10,20,10,而我们想的是10,20,20.为什么呢?
//这是一种编译器的优化可以把上段程序改成如下
//加入volatile防止编译器的优化,这时的输出就是10,20,20了
void Test()
{
    volatile  const  int a=10;
    cout<<a<<endl;
    int*  p=const_cast<int*>(&a);
    *p=20;
    cout<<*p<<endl;
    cout<<a<<endl;
}



//关键词4c++引入
//dynamic_cast用于将父类对象的指针或引用转换为子类对象的指针或引用(动态转换),为什么要这样做呢
//我们可以通过这种方法知道指针到底是指向父类的,还是指向子类的。
//注:向上转换:子类对象指针-》父类指针/引用(不需要转换)
//向下转型:父类对象指针-》子类对象指针/引用(用dynamic_cast转型是安全的)


//1,dynamic_cast只能用于含有虚函数的类。
//2.dynamic_cast 会先检查是否能转换成功,能转换成功则转换,不能则返回0


class  A
{
public:
    Virtual  void f()
    {
        cout<<“A::f”<<endl;
    }
    int _a; 
};

class  B:public  A
{
public:
    Virtual  void f()
    {
          cout<<“B::f”<<endl;
    }
    int _b; 
};
Void func (A* p)
{
    p->f();

}

void Test()
{
    A  a;
    B  b;
    func(&a);
    func(&b);
}
//这时的输出结果是
A::f
B::f
//下面我们修改下代码
class  A
{
public:
    Virtual  void f()
    {
        cout<<“A::f”<<endl;
    }
    int _a; 
};

class  B:public  A
{
public:
    virtual  void f()
    {
          cout<<“B::f”<<endl;
    }
    int _b; 
};
Void func (A* p)
{
    p->f();
    B* p1=(B*)p;
    B* p2=dynamic_cast<B*>(p);
    printf (“%p,%p\n”,p1,p2)
}

void Test()
{
    A  a;
    B  b;
    func(&a);
    func(&b);
}

//这时输出的是
A::f
001CFCE0 00000000//可以看到第一种转化转化出来了,第二个没有返回0,第二个会更安全
                 //dynamic_cast 会先检查是否能转换成功,能转换成功则转换,不能则返回0
B::f
003EF980,003EF980    //如果本身是子类向子类就是没有问题的

最好要附加一个关键字

如下代码构成的场景

class  AA
{
public:
    AA(int a)
        :_a(a)
    {}
protected:
    int _a;
}

void FAA(AA  a)
{

}

int main()
{
    AA  a1(10);
    AA  a2=20;//发生了隐式类型的转换---具有单参数构造函数的类型
//先用20 构造了一个AA类型的对象,在用这个对象拷贝构造a2;因为这个临时对象是具有常属性的可以这样验证
//const AA&  a2=20;没有报错说明确实产生了具有常属性的中间变量
//但其实大多数编译器都会有优化
    FAA(a1);
    FAA(30);
}
下面我们来修改一下程序
class  AA
{
public:
    AA(int a)
        :_a(a)
    {
        cout<<“构造”<<endl;
    }
     AA(const AA& a)
    {
        cout<<“拷贝构造”<<endl;
    }
protected:
    int _a;
}

void FAA(AA  a)
{

}

int main()
{
    AA  a1(10);
    AA  a2=20;
    FAA(a1);
    FAA(30);
}
//运行的结果是
//        构造
//        构造
//        拷贝构造
//        构造
//运行一下我们可以看到   AA a2=20;时   并没有发生一次拷贝构造,一次构造
//仅仅发生了一次构造。所以说是经过了优化
//但是官方没有规定是否一定要优化,所以不优化也没错



//下面我们来加上关键字看会发生什么
class  AA
{
public:
    explicit AA(int a)//不想让优化发生(不想发生隐式类型的转换),加上关键字explicit
        :_a(a)
    {
        cout<<“构造”<<endl;
    }
     AA(const AA& a)
    {
        cout<<“拷贝构造”<<endl;
    }
protected:
    int _a;
}

void FAA(AA  a)
{

}

int main()
{
    AA  a1(10);
    AA  a2=20;
    FAA(a1);
    FAA(30);
}
//这时就会报错,无法从int 转化为  AA。

猜你喜欢

转载自blog.csdn.net/a15929748502/article/details/82177897