typeA x = 强制类型转换符 <typeB> (y)
动静结合,底层常量
主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换
用法
其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。
不能用于内置的基本数据类型的强制转换。
转换结果
使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。
安全的向下转型(Safe Downcasting)
向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。
在C++中,编译期的类型转换有可能会在运行时出现错误,特别是涉及到类对象的指针或引用操作时,更容易产生错误。Dynamic_cast操作符则可以在运行期对可能产生问题的类型转换进行测试。
class base { public: virtual void m() { cout << "m" << endl; } }; class derived : public base { public: void f() { cout << "f" << endl; } }; int main() { derived* p; base* q=new derived; //p = static_cast<derived*>(new base); //运行时错误 //p = dynamic_cast<derived*>(new base); //不会输出,因为向下转换失败 p = dynamic_cast<derived*>(q); //输出m f,因为原来就是指向derived类型 p->m(); p->f(); return 0; }
用法
用来移除变量的const或volatile限定符。
用法
volatile 关键字:
用于修饰变量,表示变量随时可能变化,每次使用它时系统必须重新从它所在的内存读取数据
可以防止编译器访问优化,可以保证对特殊地址的稳定访问,如寄存器变量或多线程下的变量
编译器访问优化:
当编译器短时间内两次访问同一变量时,会把变量从内存装入 CPU 寄存器中,从而直接访问寄存器里的数据加快访问速度
用来处理无关类型之间的转换;它会产生一个新的值,这个值会有与原始参数(expressoin)有完全相同的比特位。
用法
在使用reinterpret_cast强制转换过程仅仅只是比特位的拷贝,因此在使用过程中需要特别谨慎!
C++中类的拷贝有两种:深拷贝,浅拷贝:当出现类的等号赋值时,即会调用拷贝函数
在未定义显示拷贝构造函数的情况下,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。
当数据成员中没有指针时,浅拷贝是可行的;
当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次析构函数,而导致指针悬挂现象,所以,此时,必须采用深拷贝。
深拷贝与浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来储存数据,从而也就解决了指针悬挂的问题。简而言之,当数据成员中有指针时,必须要用深拷贝
又称为宏代换,宏替换
#define 宏名 字符串 //不带参数的宏定义,仅符号常量代换 #define 宏名(参数表)字符串 //带参数的宏定义 //多行宏定义 #define ADD(m,n)\ (m+n)
常量传播是在编译优化时, 能够将计算出结果的变量直接替换为常量。
int a = 1; printf("%d",a); //优化后 printf("%d",1);
多个变量进行计算时,而且能够直接计算出结果,那么变量将由常量直接替换。常量折叠表面上的效果和宏替换是一样的
使用std::ref
可以在模板传参的时候传入引用,否则无法传递
void func(int& num) { cout<<num+1; } int answer = 1; thread thd{func, ref(answer)};
include<文件名> 和 #include"文件名" 的区别:
extern "C" 表示按照C语言方式进行连接。
加上extern "C"之后,C++编译器就会按照C语言的符号修饰规则对函数进行修饰,这样连接器就能够正确解析。
C语言
sizeof(1 == 1) === sizeof(1)按照整数处理,所以是4字节,这里也有可能是8字节(看操作系统)
C++
因为有bool 类型
sizeof(1 == 1) == sizeof(true) 按照bool类型处理,所以是1个字节