static_cast
该运算符把expression转化为type_name类型,static_cast在编译时使用类型信息执行转换,在转换执行必要时的检测(如指针越界,类型检查),但没有运行时类型检查来保证转换的安全性
- 用于基本类型检查,如把int转换为char,把int转换为enum
enum WeekType{sun=0,Mon=1,Tues=2,Wed=3,Thus=4,Fir=5,Sat=6};
int main()
{
int a = 10;
char ch = 'x';
double dx = 12.34;
a = static_cast<int>(ch);
a = static_cast<int>(dx);
WeekType x = Mon;
a = x;
x = static_cast<WeekType>(a);
}
- 指针转换的限制
- 可以就void*转换为其它类型
int main()
{
int a = 10;
int* ip = nullptr;
double* dp = nullptr;
void* vp = &a;
ip = static_cast<int*>(vp);
dp = static_cast<double*>(dp);
return 0;
}
- 弃值表达式
int main()
{
int a = 10, b = 20;
static_cast<void>(a + b);
}
- 左值到右值
1.先补充一个小知识点,移动语义
class PtrInt
{
private:
int* pval; // new .heap ; stack . data;
public:
PtrInt(int* p = nullptr) :pval(p)
{
cout << "create Ptrint:" << this << endl;
}
~PtrInt()
{
delete pval;
pval = nullptr;
cout << "Destory Ptrin:t" << this << endl;
}
PtrInt(const PtrInt& it) :pval(new int(0)) //拷贝构造函数
{
*pval = *it.pval;
//*pval = it.*pval;
}
PtrInt& operator=(const PtrInt& it) //拷贝赋值函数
{
if (this != &it)
{
delete pval;
pval = new int(*it.pval);
//pval = it.pval;
}
cout << "Copy create Ptrint:" << this << endl;
return *this;
}
PtrInt(PtrInt&& it) :pval(it.pval) //移动构造函数
{
it.pval = nullptr;
cout << "move copy create Ptrint:" << this << endl;
}
PtrInt& operator=(PtrInt&& it) //移动赋值函数
{
if (this != &it)
{
delete[]pval;
pval = it.pval;
it.pval = nullptr;
}
cout << "Copy operator Ptrint:" << this << endl;
return *this;
}
};
PtrInt func(int x)
{
PtrInt tmp(new int(x));
return tmp;
}
int main()
{
PtrInt a(new int(10));
a = func(100);
return 0;
}
运行结果:
2.左值与右值之间的转换
#include<iostream>
using namespace std;
class PtrInt
{
private:
int* pval; // new .heap ; stack . data;
public:
PtrInt(int* p = nullptr) :pval(p)
{
}
~PtrInt()
{
delete pval;
pval = nullptr;
}
PtrInt(const PtrInt& it) :pval(new int(0)) //拷贝构造函数
{
*pval = *it.pval;
//*pval = it.*pval;
}
PtrInt& operator=(const PtrInt& it) //拷贝赋值函数
{
if (this != &it)
{
delete pval;
pval = new int(*it.pval);
//pval = it.pval;
}
return *this;
}
PtrInt(PtrInt&& it):pval(it.pval) //移动构造函数
{
it.pval = nullptr;
}
PtrInt& operator=(PtrInt&& it) //移动赋值函数
{
if (this != &it)
{
delete[]pval;
pval = it.pval;
it.pval = nullptr;
}
return *this;
}
};
int main()
{
const PtrInt a(new int(10)), b(new int(20)), c(new int(30));
PtrInt x(a);
PtrInt aa((PtrInt&&)a); //耍流氓行为,直接强转,不会报错
//PtrInt bb(static_cast<PtrInt&&>(b)); //会报错,不能实现常对象的转换
PtrInt bb(static_cast<PtrInt&&>(const_cast<PtrInt&>(b)));
PtrInt cc(std::move(c)); //移动语义,此时常对象,调用的是拷贝构造函数
return 0;
}
- 用于类层次结构中的基类和派生类之间指针和引用的转化(上行转换是安全的,下行转换由于没有动态类型检查,是不安全的)
class object
{
private:
int value;
public:
object(int x = 0) :value(x) {}
void func() {}
};
class Base :public object
{
private:
int num;
public:
Base(int x=0):object(x+10),num(x){}
void show()const{}
};
int main()
{
object* op = nullptr;
Base* bp = nullptr;
Base base;
object obj;
op = &obj;
bp = &base;
op = static_cast<object*>(&base);
bp = static_cast<Base*>(&obj);
return 0;
}
const_cast
- 用于去除变量的只读属性
- 强制转换的目标必须是指针或者引用
int main()
{
const int a = 10;
const int* cp = &a;
const int& cr = a;
int* p = const_cast<int*>(cp);
int& r = const_cast<int&>(cr);
int&& rr = const_cast<int&&>(a);
return 0;
}
class Int
{
int value;
public:
Int(int x = 0) :value(x) {}
~Int() {}
void SetValue(int x) { value = x; }
int GetValue()const { return value; }
};
int main()
{
const Int a(10);
cout << a.GetValue() << endl;
Int* ip = const_cast<Int*>(&a);
Int& b = const_cast<Int&>(a);
ip->SetValue(100);
cout << a.GetValue() << endl;
b.SetValue(200);
cout << a.GetValue() << endl;
}
reinterpret_cast(重新解释)
有点类似于C语言的强转
特点:
用于指针类型间强制转化
用于整数和指针类型间的强制转化
int main()
{
int a = 0x6162634;
char* cp = reinterpret_cast<char*>(&a);
cout << *cp << endl;
cp += 1;
cout << *cp << endl;
cp += 1;
cout << *cp << endl;
cp += 1;
cout << *cp << endl;
cp += 1;
}
class object
{
private:
int value;
public:
object(int x=0):value(x){}
~object(){}
int& Value() { return value; }
const int& Value()const { return value; }
};
int main()
{
object obj(10);
int* p = reinterpret_cast<int*>(&obj);
int& a = reinterpret_cast<int&>(obj);
*p = 100;
cout << obj.Value() << endl;
a += 100;
cout << obj.Value() <<endl;
return 0;
}
dynamic_cast
必须是公有继承,基类要有虚函数
1.与C++支持其他强制转化的不同的是,dynamic_cast是在运行时执行的动态类型转换
2.如果针对指针类型的dynamic_cast失败,则dynamic_cast的结果是nullptr
3.如果针对引用类型的dynamic_cast失败,则dynamic_cast会抛出一个异常
4.在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的
5.在进行下行转换时,dynamic_cast具有类型检查功能,比static_cast更安全
6.上行转换如果没有虚函数,都属于静态类型转换
7.dynamic_cast的操作数必须是指向完整类类型的指针
//上相转换
class object
{
private:
int value;
public:
object(int x = 0) :value(x) {}
void func() { cout << "value" << value << endl; }
};
class Base :public object
{
private:
int num;
public:
Base(int x = 0) :object(x + 10), num(x) {}
void show()const { void func() { cout << "num" <<num << endl; } }
};
int main()
{
object* op = nullptr;
object obj(10);
Base base(10);
op = &obj;
op = &base;
op = dynamic_cast<object*>(&base);
op = static_cast<object*>(&base);
}
指针类型转换
//下行转换
class object
{
private:
int value;
public:
object(int x = 0) :value(x) {}
virtual void func() { cout << "value" << value << endl; }
};
class Base :public object
{
private:
int num;
public:
Base(int x = 0) :object(x + 10), num(x) {}
void func() { cout << "num" << num << endl; }
};
int main()
{
Base base;
object* pobj = &base;
Base* pa = dynamic_cast<Base*>(pobj);
Base* pb = static_cast<Base*>(pobj);
object obj;
pobj = &obj;
pb = static_cast<Base*>(pobj);
pb->func();
pa = dynamic_cast<Base*>(pobj);//动态转换 pa=nullptr
pa->func(); //报错,转化的时候检查RTTI,运行时类型识别信息
}
引用类型转换
//下行转换
class Object
{
private:
int value;
public:
Object(int x = 0) :value(x) {}
virtual void func() { cout << "value" << value << endl; }
};
class Base :public Object
{
private:
int num;
public:
Base(int x = 0) :Object(x + 10), num(x) {}
void func() { cout << "num" << num << endl; }
};
int main()
{
Object object;
Base base;
Object& obj = object;
try
{
Base& ba = dynamic_cast<Base&>(obj);
ba.func();
}
catch (std::bad_cast& x)
{
cout << x.what() << endl;
}
return 0;
}
运行结果:
3.关于RTTI的用途以及根据动态类型进行分类
class Goods
{
float _weight; // 重量
public:
Goods(float wt) : _weight(wt) {}
virtual ~Goods() { std::cout << "~Trash()" << std::endl; }
float GetWeight() const { return _weight; }
virtual float GetPrice() const = 0; // 价格
};
// 铜
class Copper : public Goods
{
static float price;
public:
Copper(float wt) : Goods(wt) {}
float GetPrice() const { return price ; }
static void SetPrice(float newprice) {
price = newprice;
}
};
float Copper::price = 2.80;
// 纸张
class Paper : public Goods
{
static float price;
public:
Paper(float wt) : Goods(wt) {}
float GetPrice() const { return price ; }
static void SetPrice(float newprice) {
price = newprice;
}
};
float Paper::price = 0.20;
// 玻璃
class Glass : public Goods
{
static float price;
public:
Glass(float wt) : Goods(wt) {}
float GetPrice() const { return price ; }
static void SetPrice(float newprice) {
price = newprice;
}
};
float Glass::price = 0.32;
template<class Container >
void sumPrice(Container& bin)
{
float total = 0;
for (auto p : bin)
{
//cout << typeid(x).name() << endl;
total += p->GetPrice() * p->GetWeight();
cout << "wight of : " << typeid(*p).name() << " = " << p->GetWeight() << endl;
}
cout << "Total price = " << total << endl;
}
int main()
{
srand(time(0)); // Seed the random number generator
vector<Goods*> bin;
int n = rand() % 200; // 0 199
for (int i = 0; i < n; i++)
{
switch (rand() % 3)
{
case 0:
bin.push_back(new Copper((rand() % 1000) / 10.0));
break;
case 1:
bin.push_back(new Paper((rand() % 1000) / 10.0));
break;
case 2:
bin.push_back(new Glass((rand() % 1000) / 10.0));
break;
}
}
// Note: bins hold exact type of object, not base type:
vector<Glass*> glassBin;
vector<Paper*> paperBin;
vector<Copper*> coppBin;
vector<Goods*>::iterator sorter = bin.begin();
// Sort the Trash:
while (sorter != bin.end())
{
Copper* cp = dynamic_cast<Copper*>(*sorter);
Paper* pa = dynamic_cast<Paper*>(*sorter);
Glass* gp = dynamic_cast<Glass*>(*sorter);
if (cp) coppBin.push_back(cp);
else if (pa) paperBin.push_back(pa);
else if (gp) glassBin.push_back(gp);
++sorter;
}
sumPrice(coppBin);
sumPrice(paperBin);
sumPrice(glassBin);
sumPrice(bin);
for (auto& x : bin)
{
delete x;
x = nullptr;
}
}