*什么是虚函数?什么是纯虚函数?
虚函数:virtual void func() {}; 有实现,为了使用多态。
纯虚函数:virtual void func() = 0; 无实现,为了定义接口。
*什么是抽象类?
有纯虚函数的类为抽象类。抽象类不能实例化。
*构造函数为什么一般不定义为虚函数?而析构函数一般写成虚函数的原因 ?
构造函数不能声明为虚函数
因为创建一个对象时需要确定对象的类型,而虚函数是在运行时确定其类型的。而在构造一个对象时,由于对象还未创建成功,编译器无法知道对象的实际类型,是类本身还是类的派生类等等
虚函数的调用需要虚函数表指针,而该指针存放在对象的内存空间中;若构造函数声明为虚函数,那么由于对象还未创建,还没有内存空间,更没有虚函数表地址用来调用虚函数即构造函数了
析构函数最好声明为虚函数
首先析构函数可以为虚函数,当析构一个指向派生类的基类指针时,最好将基类的析构函数声明为虚函数,否则可以存在内存泄露的问题。
如果析构函数不被声明成虚函数,则编译器实施静态绑定,在删除指向派生类的基类指针时,只会调用基类的析构函数而不调用派生类析构函数,这样就会造成派生类对象析构不完全。
*动态绑定和静态绑定 运行期 编译期
*赋值兼容规则
1·派生类的对象可以赋值给基类对象。
2·派生类的对象可以初始化基类的引用。
3·派生类对象的地址可以赋给指向基类的指针。
*重载overload,覆盖override,重写overwrite,这三者之间的区别
作用范围 相同范围 不同范围(基类和派生类) 不同范围(基类和派生类)
表示形式 参数不同 参数相同 参数相同或不同
关键字 无 virtual 无
*new、delete、malloc、free
调用构造和析构函数
运算符和库函数
*new及placememt new 异同点
placememt new不分配内存空间
*STL中的vector的实现,是怎么扩容的?
动态数组,自动扩容
vector就是一个动态增长的数组,里面有一个指针指向一片连续的空间,当空间装不下的时候,会申请一片更大的空间,将原来的数据拷贝过去,并释放原来的旧空间。当删除的时候空间并不会被释放,只是清空了里面的数据。
*C++的内存管理
栈、堆(自由存储区)、全局\静态存储区(初始化、未初始化)、常量存储区
*栈和堆
自动分配 手动分配
速度快 速度慢
小 大
*什么情况下会调用拷贝构造函数
(1)用类的一个对象去初始化另一个对象时
(2)当函数的形参是类的对象时(也就是值传递时),如果是引用传递则不会调用
(3)当函数的返回值是类的对象或引用时
*C++的四种强制转换
static_cast、
dynamic_cast、 类之间、基类需要有虚函数 上行、下行、运行时
const_cast、 强制转换指针或者引用的const或volatile限
reinterpret_cast 处理无关类型之间的转换
volatile
volatile是一个类型修饰符(type specifier).volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
*什么是野指针
野指针不是NULL指针,是未初始化或者未清零的指针,它指向的内存地址不是程序员所期望的,可能指向了受限的内存
成因:
1)指针变量没有被初始化
2)指针指向的内存被释放了,但是指针没有置NULL
3)指针超过了变量了的作用范围,比如b[10],指针b+11
*简述数组与指针的区别?
数组要么在全局\静态存储区被创建,要么在栈上被创建。
指针可以随时指向任意类型的内存块。
(1)修改内容上的差别
char a[] = “hello”;
a[0] = ‘X’;
char *p = “world”; // 注意p 指向常量字符串
p[0] = ‘X’; // 编译器不能发现该错误,运行时错误
- 用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p 所指的内存容量。
C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12 字节
cout<< sizeof(p) << endl; // 4 字节
计算数组和指针的内存容量
void Func(char a[100])
{
cout<< sizeof(a) << endl; // 4 字节而不是100 字节
}
*多态的原理
虚函数 虚函数表(类) 虚指针(对象)
*单链表反转