c++新特性
–
强制转换
分类及实例
分类
实例展示
#include<iostream>
using namespace std;
int main() {
int* pa = nullptr;
float* pf = nullptr;
int ii = 20;
float ff = 2.22;
const int constNum = 11;
/*
static_cast 实现无条件静态类型转换.
但是不相关类型不能转换 如:
int i = static_cast<int>(pa);
虽然都是4字节,但是一个是指针,一个是变量.
*/
ff = static_cast<float>(ii);
/*
reinterpret_cast 重新解释类型,只能实现指针类型转换
pf = static_cast<float*>(pa) 类型转换无效
*/
pf = reinterpret_cast<float*>(pa);
/*
const_cast可以去掉常量的const属性。
内容必须是指针、引用或者是、指向对象成员的指针
*/
int& temp = const_cast<int&>(constNum);
return 0;
}
dynamic_cast 动态类型识别,判断父类指向的时哪一个子类对象
- 指针,转换失败返回nullptr
- 引用,转换失败抛std::bad_cast 异常
#include<iostream>
using namespace std;
class Animal
{
public:
virtual void cry() = 0;
virtual ~Animal() {};
void co() {};
};
class Dog :public Animal
{
public:
void cry() override
{
cout << "小狗:汪汪~" << endl;
}
void seeHome()
{
cout << "看家" << endl;
}
};
class Cat :public Animal
{
public:
void cry() override
{
cout << "小猫:喵喵喵~" << endl;
}
void catchMouse()
{
cout << "抓老鼠" << endl;
}
};
//指针可以直接判断
void obj(Animal* base)
{
base->cry();
//base == Cat or Dog;
//狗,看家
Dog* dog = dynamic_cast<Dog*>(base);
if (dog)
{
dog->seeHome();
}
//猫,抓老鼠
Cat* cat = dynamic_cast<Cat*>(base);
if (cat)
{
cat->catchMouse();
}
}
//引用无法判断,会抛异常
void obj(Animal& base)
{
base.cry();
//狗,看家
Dog& dog = dynamic_cast<Dog&>(base);
dog.seeHome();
//猫,抓老鼠
Cat& cat = dynamic_cast<Cat&>(base);
cat.catchMouse();
}
int main()
{
Dog* pd = new Dog;
Cat* pc = new Cat;
obj(pd);
obj(pc);
delete pd;
delete pc;
return 0;
}
decltype类型推导
decltype 是“declare type”的缩写,译为“声明类型”,它和 auto 的功能一样,都用来在编译时期进行自动类型推导。
auto 的语法格式比 decltype 简单,所以在一般的类型推导中,使用 auto 比使用 decltype 更加方便。但是auto 只能用于类的静态成员,不能用于类的非静态成员(普通成员),如果我们想推导非静态成员的类型,这个时候就必须使用 decltype 了。
使用方法:
auto varName = value;
decltype(exp) varName = value;
//varName 表示变量名,value 表示赋给变量的值,exp 表示一个表达式。
auto 根据=
右边的初始值 value 推导出变量的类型,而 decltype 根据 exp 表达式推导出变量的类型,跟=
右边的 value 没有关系。所以,auto 要求变量必须初始化,而 decltype 不要求。
decltype推导规则
exp 注意事项
原则上讲,exp 就是一个普通的表达式,它可以是任意复杂的形式,但是我们必须要保证 exp 的结果是有类型的,不能是 void;例如,当 exp 调用一个返回值类型为 void 的函数时,exp 的结果也是 void 类型,此时就会导致编译错误。
int a = 0;
decltype(a) b = 1; //b 被推导成了 int
decltype(10.8) x = 5.5; //x 被推导成了 doublecpp
decltype(x + 100) y; //y 被推导成了 double
上面的例子让我们初步感受了一下 decltype 的用法,但你不要认为 decltype 就这么简单,它的玩法实际上可以非常复杂。当程序员使用 decltype(exp) 获取类型时,编译器将根据以下三条规则得出结果:
**实例1:**如果 exp 是一个不被括号( )
包围的表达式,那么 decltype(exp) 的类型就和 exp 一致,这是最普遍最常见的情况。
int main()
{
int n = 0;
const int &r = n;
Student stu;
decltype(n) a = n; //n 为 int 类型,a 被推导为 int 类型
decltype(r) b = n; //r 为 const int& 类型, b 被推导为 const int& 类型
return 0;
}
实例2: exp 为函数调用,那么 decltype(exp) 的类型就和函数返回值的类型一致。
//函数声明
int fun_int(int);
int* fun_int_ptr(int);
int& fun_int_ref(int);
const int& fun_cint_ref(int);
int main()
{
int val = 66;
decltype(fun_int(1)) a = val; //a 的类型为 int
decltype(fun_int_ptr(2)) b = &val; //b 的类型为 int*
decltype(fun_int_ref(3)) c = val; //c 的类型为 int&
decltype(fun_cint_ref(4)) x = val; //x 的类型为 const int&
return 0;
}
实例3: 如果 exp 是一个左值,或者被括号( )
包围,那么 decltype(exp) 的类型就是 exp 的引用;
int main()
{
int val = 66;
//带括号
decltype(val) a = 1; //int
decltype((val)) b = val; //int&
//左值和右值
int m = 0, n = 0;
decltype(m + n) c = 66; //int 因为,a+b会产生一个右值 (m+n)=5;//错误
decltype(m += n) d = val; //int& m+=n产生一个左值m (m+=n) = 5;//正确
return 0;
}
返回值类型后置
在泛型编程中,可能需要通过**参数的运算 decltype(a + b)**来得到返回值的类型。考虑下面这个场景:
template <typename R, typename T, typename U>
R add(T t, U u)
{
return t+u;
}
int a = 1;
float b = 2.0;
auto c = add<decltype(a + b)>(a, b);
但是外部其实并不知道参数之间应该如何运算,只有 add 函数才知道返回值应当如何推导。
那么,在 add 函数的定义上能不能直接通过 decltype 拿到返回值呢?
template <typename T, typename U>
decltype(t + u) add(T t, U u) // error: t,u尚未定义
{
return t + u;
}
“error: t,u尚未定义”,所以在 C++11 中增加了**返回类型后置(trailing-return-type,又称跟踪返回类型)**语法,将 decltype 和 auto 结合起来完成返回值类型的推导。可以写成:
template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u)
{
return t + u;
}
为了进一步说明这个语法,再看另一个例子:
int& foo(int& i) { return i; }
float foo(float& f) { return f; }
template <typename T>
auto func(T& val) -> decltype(foo(val))
{
return foo(val);
}
//让func函数根据foo的具体返回类型,推导自己的返回类型(int& 和float)
//如果不写 -> decltype(foo(val)) 那么func函数将不会返回引用类型
如果说前一个例子中的 add auto自动推导返回类型还行,那么这个例子对于 C++ 而言就是不可能完成的任务了(涉及到)。
在这个例子中,使用 decltype 结合返回值后置语法很容易推导出了 foo(val) 可能出现的返回值类型,并将其用到了 func 上。
返回值类型后置语法,是为了解决函数返回值类型依赖于参数而导致难以确定返回值类型的问题。