1、指出下面的错误
int main()
{
char* a = "abcdefgh"; //指针a指向常量区
a[1] = "B" ; //修改了常量,故错误;
printf("%s\n",a);
}
//后果:程序崩溃
2、进程与线程
定义: 进程:具有独立功能的程序关于某个数据集合上的一次运行活动、进程是系统资源分配和调度的一个基本单位。
线程:是进程的实体,是cpu调度和分配的最小单位。它是比进程更小的独立运行的最小单位,线程基本上不拥有系统资源。只拥有一点在运行时不可少的资源。但它可以与同属一个进程的其它的线程共享进程所拥有的全部资源。
关系:一个线程可以创建和销毁另一个线程;同时一个进程的多个线程可以并发执行。
相对于进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
区别:进程拥有自己的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生引向,而线程只是进程的不同的执行路径。
线程拥有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程崩溃等于整个进程崩溃。则多进程比多线程的安全,但进程在切换时消耗资源大,效率低。
对于一些要求同事进程又要共享某些变量的并发操作、只能用线程,不能用进程。
1、一个程序至少有一个进程,一个进程至少有一个线程。
2、线程的划分尺度小于进程,使得多线程的程序并发性高。
3、进程在执行中拥有独立的内存单元,而线程的共享极大地提高了程序的效率。
4、每个独立的线程有程序入口、顺序执行序列和程序出口。但线程不能独立执行,必须依赖应用程序,由多个程序提供多个线程执行控制。
5、多线程的意义在于一个应用程序中,有多个执行的部分可以同时执行。但操作系统并没有将多个线程看做独立的应用,来实现进程的调度和管理以及资源分配。
优缺点:
进程:消耗资源大,利于资源的管理和保护,进程可以跨机器迁移。
线程:消耗资源小,不利于资源的管理和保护、适用于SMP机器上运行。
3 const_cast static_cast dynamic_cast reinterpreter_cast
const_cast: 去掉类型的const或volatile属性
static_cast: 无条件转换,静态类型转换。用于:
1、基本类型之间数据类型转换。
2、基类和子类之间的数据类型转换。(当基类转子类是数据不安全,建议使用dynamic_cast)
3、把空指针转换为任意类型的指针。
4、把任何类型的表达式转换为woid类型
5、static_cast不能去掉类型的const、volitale属性。
daynamic_cast:动态数据类型转换,运行时安全类型检查(转换失败返回NULL)
1、安全基类和子类之间类型转换。
2、必须有虚函数
3、相同基类、不同子类之间的交叉转换,但结果为NULL
reinter_cast:仅仅重新解释类型,但没有进行二进制的转换:
1、转换类型必须是指针、引用、算术类型、函数指针或成员指针。
2、在比特位级别上进行转换。它可以吧一个指针转换为一个整数,也可以把一个整数转换为一个指针。但不能将非32bit的实例转换为指针
3、最普通的用途就是在函数指针类型之间进行转换。
4、很难保证移植性
总结
去const属性用const_cast
基本类型转换用static_cast
多态之间的类型转换用daynamic_cast。
不同类型的指针类型转换用reinterpreter_cast
4、虚函数在内部的实现
1、当内部有虚函数,则编译器会在编译期间产生一个函数表,并在该内的对象中隐式声明一个指针变量指向该函数表。
2、每个类自己的虚函数入口都在这种表中维护,调用方法时隐式的传入一个this指针。然后系统会跟局this指针找到对应的指针变量,重而找到对应的虚函数表,找到对应的方法的地址,然后去调用这个方法。
3、虚函数表存放重新虚函数,当基类指针指向派生内对象时,调用虚函数时都会根据这个指针来选择函数,而基类的虚函数在派生类已经改写了或者已经不存在了,所以它只能调用派生类虚函数版本。
5 NULL与nullptr的区别
NULL是一个预处理器变量,值为0
nullptr是一个字面常量,可以转化为任何其它类型的指针
在c语言中任何类型的指针可以(隐式的)转换为void*型,反过来也行。
在C++中void*类型的指针不能转换为别的类型的指针