赋值运算符左右两侧类型不同
形参与实参类型不匹配
返回值类型与接收返回值类型不一致
编译器在编译阶段自动进行,能转就转,不能转就编译失败
C语言允许**意义相近的类型(比如整形家族和浮点型家族)**进行隐式类型转换:
隐式类型转换可以发生在赋值和关系运算符之间
整形转整形存在: 整形提升和整形截断
整形和浮点型转换: 丢失精度
用户自己处理
C语言允许意义不相近的类型进行显式类型转换:
意义不相近但转换后有意义
比如指针转整形 指针是一个地址 地址编号有大小 有意义
一个类转整形:无意义
void Problem(size_t pos, char ch)
{
string _str[10] = { 0 };
size_t _size = 5;
//若pos为0 end为unsigned int 永远 >=0 -- 死循环
//size_t end = _size - 1;
//
//改进: 搞成int 仍然不行 因为在关系运算符 >= 会发生隐士类型转换
//-1与0比较 -1从u_int->int -1 => MAX_INT [ ]越界访问
//我们只能改变end的始终取值范围 来避免这种情况
int end = _size - 1;
while (end >= pos)
{
_str[end + 1] = _str[end];
--end;
}
}
C++自己搞了一套 说明C语言的不够好 不好在哪里呢?
编译器隐式类型转换可用static_cast,但它不能用于两个不相关的类型进行转换
int main()
{
double d = 12.34;
int a = static_cast<int>(d);
cout << a << endl; //12
int* p = &a;
//int address = static_cast(p); 不支持
return 0;
}
为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型
一个问题
pb仅仅是把10当成一个地址去指向
但是地址为10的空间没有数据
是无效的 不允许访问和修改
删除变量的const属性,进行赋值
int main()
{
//int b = 10;
//int* pb = reinterpret_cast(b);
cout << *pb << endl;
//const局部变量 存在内存的栈上 不可直接修改 但可间接修改
//某些编译器认为const变量不会被修改 于是直接放进寄存器 使读的速度快 而不可写
const int a = 2;
int* p = const_cast<int*>(&a);
//某些编译器: 内存中的a被间接修改 但是寄存器上的a没有被改
*p = 3;
cout << a << endl; //VS:直接访问a的2
cout << *p << endl;
return 0;
}
const_cast将 const int* --> int* 很危险!!!
const int a = 2;
这是一个常量定义,a
被声明为一个常量,其值被固定为2,不能在程序运行过程中被改变。在整个程序执行过程中,试图修改a
的操作都是非法的。
volatile const int a = 2;
这里将a
声明为volatile const
类型,表示这是一个同时具有常量和易失性(volatile)特性的变量。volatile
关键字的作用是告诉编译器,该变量的值可能会在不同的时间点被意外更改,仅依赖于编译器优化的常量值可能会导致问题。因此,编译器不会对a
进行一些优化操作,如缓存变量值或重新排序指令,以确保对a
的每次访问都从其内存地址读取最新的值。
综上所述,const int a = 2;
声明的a
是一个常量,而volatile const int a = 2;
声明的a
是一个常量且具有易失性特性。
子类对象可以赋值给父类对象[切割赋值]
父类的指针或引用可以指向子类
父类对象无法转换成子类对象
class A
{
public:
int _a = 0;
};
class B : public A
{
public:
int _b = 1;
};
int main()
{
int i = 0;
//double tmp = i; double d = tmp;
double d = i;
//double& rd = i;
// 1.引用的是临时变量
// 2.临时变量具有常性
const double& rd1 = i; //C语言
const double& rd2 = static_cast<double>(i); //C++
//类的继承没有产生tmp
//因为这里有类的切割赋值
B bb;
//子类对象赋值给父类对象
A aa1 = bb;
//父类的指针或引用指向子类对象
A& ra1 = bb;
父类对象无法转换成子类对象
B bb = aa;
B bb = (B)aa;
B bb = dynamic_cast<B>(aa);
}
本来 父类类型指针可以指向父类/子类对象 但是即便指向子类对象却不可以访问子类对象的数据
由此引发了父类类型指针如何转换成子类类型指针的问题
dynamic_cast通过将指向子类对象的父类指针转成指向子类对象的子类指针 从而使得可以访问子类对象的数据
int main()
{
A aa;
B bb;
//父类指针指向父类对象
A* pa1 = &aa;
pa1->_a;
//父类指针指向子类对象
//父类指针指向了子类中父类的那一部分
A* pa2 = &bb;
pa2->_a;
//pa2->_b; 访问不了 pa1/pa2不管指向谁都是A类型的 只能访问_a
//父类指针强制转换成子类指针
B* pb = (B*)pa1;
pb->_a;
//pb->_b;
//仍然无法访问_b: 引发异常 存在越界风险
return 0;
}
dynamic_cast的引出
class A
{
public:
virtual void f(){}
public:
int _a = 0;
};
class B : public A
{
public:
int _b = 1;
};
//p指向父类对象: 父类指针指向父类对象
//p指向子类对象: 父类指针指向子类对象 但只可以访问父类数据
void fun(A* p)
{
// p指向父类 不能转换 转换表达式返回nullptr
// p指向子类 可以转换 转换表达式返回正确的地址
B* pb = dynamic_cast<B*>(p);
//dynamic_cast安全性在于它不仅可以判断转换成功 而且转换成功后还可以访问
//B* pb = (B*)p; //都可以转换成功 但是不可成功访问
if (pb == nullptr)
{
cout << "当前父类类型指针指向父类对象 父类类型指针 没有转换成 子类类型指针" << endl;
//防止p传进来的就是nullptr
if (p != nullptr)
{
p->_a = 1;
cout << "p->_a: " << p->_a << endl;
}
else
{
cout << "且p指针本就是一个nullptr!" << endl;
}
}
else
{
cout << "当前父类类型指针指向子类对象 父类类型指针 成功转换成 子类类型指针" << endl;
pb->_a = 1;
pb->_b = 2;
cout << "pb->_a: " << pb->_a << endl << "pb->_b: " << pb->_b << endl;
cout << "p: " << p << " --- " << "pb: " << pb << endl;
}
}
int main()
{
A aa;
B bb;
//父类指针指向父类对象
A* pa1 = &aa;
pa1->_a;
//父类指针指向子类对象
//父类指针指向了子类中父类的那一部分
A* pa2 = &bb;
pa2->_a;
//pa2->_b; 访问不了 pa1/pa2不管指向谁都是A类型的 只能访问_a
//父类指针强制转换成子类指针
B* pb = (B*)pa1;
pb->_a;
//pb->_b;
//仍然无法访问_b: 引发异常 存在越界风险
fun(&aa);
cout << endl;
fun(&bb);
cout << endl;
fun(nullptr);
return 0;
}
dynamic_cast用于将一个父类类型的指针/引用转换为子类类型的指针或引用(动态转换)
向上转型:子类类型的指针或引用转换为父类类型的指针/引用(不需要转换,赋值兼容规则)
向下转型:父类类型的指针/引用转换为子类类型的指针或引用(dynamic_cast转型较安全)
注意:
运行时类型识别
C++支持RTTI的方式:
template<class T1, class T2>
void Func(T1 a, T2 b)
{
decltype(a * b) x;
cout << typeid(x).name() << endl;
}
int main()
{
//关键字decltype
//将变量的类型 声明为 表达式指定的类型
const int X = 1;
double y = 2.2;
cout << typeid(x * y).name() << endl;
decltype(x* y) j ;
decltype(&x) k ;
cout << typeid(j).name() << endl;
cout << typeid(k).name() << endl;
//使用场景
//1.传类型
vector<decltype(x* y)> v;
//2.函数内部
Func(1, 'a');
return 0;
}