第一篇见C++ 基础知识 问答题(一)_绿风天空的博客-CSDN博客
第二篇见https://blog.csdn.net/jmqxnxg/article/details/131773475?spm=1001.2014.3001.5501
Part 1是题目, Part2是答案。
Part 1
42. 列表初始化是什么?
43. 纯虚函数是什么?
44. 抽象类是什么?特点是什么?
45. 虚函数指针是什么?虚函数表是什么?
46.多继承会造成什么问题?怎么解决?
47.虚继承是什么?
48.接口类是什么?
49.类模板是什么?
50.类模板中可以使用虚函数吗?
51.下列内存分配函数是使用方法和作用分别是什么:malloc、calloc、realloc、alloca
52.new和delete操作符分别完成了什么操作?
53.delete this合法吗?
54.如何定义一个只能在堆上生成对象的类?
55.如何定义一个只能在栈上生成对象的类?
56.shared_ptr是什么?
57.weak_ptr是什么?
58.unique_ptr是什么?
59.强制类型转换运算符有哪些?作用分别是什么?
60.typeid是什么?typeinfo什么?
Part2
42. 列表初始化是什么?
使用花括号列表来初始化对象,对应的构造函数接受 std::initializer_list<T> 类型的参数
Student<int> a = {9,8,6,5};
43. 纯虚函数是什么?
在基类中没有具体实现的虚函数,而在派生类中来实现(当然派生类中也可以继续不实现)
格式为:virtual 声明=0;
virtual void func(int t)=0;
44. 抽象类是什么?特点是什么?
抽象类包含了纯虚函数的类。
抽象类不能直接实例化,只要继承了该抽象类且实现了抽象类中的所有纯虚函数的派生类才可以实例化。
45. 虚函数指针是什么?虚函数表是什么?
包含虚函数指针的对象会有一个虚函数指针,指向该对象的类的虚函数表,在运行时绑定。
虚函数表在程序只读数据段存放虚函数指针。
每个类会有一个虚函数表,在程序编译期间创建和初始化。
如果这个类继承了另一个类,它的虚函数表会包含基类的虚函数和它自己的虚函数。
如果一个派生类重写了基类的虚函数,那么派生类的虚函数表中会覆盖掉原先基类的虚函数的地址。
46.多继承会造成什么问题?怎么解决?
会造成菱形继承问题:类B和类C都继承了类A,此时类D多继承类B和类C,在类D中就有了两份的类A的成员变量,会造成内存浪费,也会造成歧义,当你调用类A的成员变量时,编译器不确定你调用的是类B中的,还是类C中的,只能加上类名调用(B::a)。
47.虚继承是什么?
虚继承是为了解决多继承造成的问题,在上一题的例子中,如果类B和类C都虚继承了类A,此时类D再多继承类B和类C,类D中就不会出现两份类A的成员变量了。
一般的继承中,子类只有一个虚函数指针,指向一张包含了父类和子类的所有虚函数的虚表。
当虚继承时,子类中有两个虚函数指针,分别指向包含了父类的所有虚函数的虚表,和包含了子类的所有虚函数的虚表。
虚继承意味着该类愿意共享它的基类,这个共同的基类就叫虚基类。
注意点:当类B虚继承类A时,类B的子类多继承时,只会有一份A的变量,但是这不影响类B,类B多继承,不会具有该特性。
48.接口类是什么?
只包含纯虚函数的抽象类
49.类模板是什么?
类定义时不指定具体的参数类型,只用模板来占位,使用时根据给出的类型来生成对应的类。
template<typename T>
50.类模板中可以使用虚函数吗?
可以使用。但是一个类的成员模板函数不能是虚函数。
51.下列内存分配函数是使用方法和作用分别是什么:malloc、calloc、realloc、alloca
malloc的参数是字节数,返回一个void*指针,指向分配的内存。这块内存不会被初始化,所以需要程序员手动初始化。
calloc的参数是内存块数和每块内存的字节数,返回个void*指针,指向分配的内存。calloc会将这块内存初始化为0。
realloc的参数是内存指针和新的要分配的字节数,在原来的内存块上缩小或扩大内存,如果原来的内存块上无法完成扩展了,那就在一块新的内存块上分配内存,并将原来内存块上的数据复制过去,之后程序员就是用realloc返回的指针来访问原先的数据。返回的指针类型与参数指针类型相同。
alloca的参数是字节数,返回一个void*指针。在函数调用栈上分配内存,所以当函数结束调用时,alloca申请得到的内存会被自动释放。
52.new和delete操作符分别完成了什么操作?
new操作符先调用malloc分配内存,再调用类的构造函数。(使用new不需要指定内存的字节数,会自动计算所需字节数)
delete操作符先调用类的析构函数,再调用free释放内存。
53.delete this合法吗?
合法,但可能会出现很多未定义的问题。
仅当满足下列所以条件才能使用:
该对象是通过new分配内存的
该对象的声明周期已经结束,没有其他代码会再访问该对象
54.如何定义一个只能在堆上生成对象的类?
将类的析构函数设置为private。
C++是静态绑定的语言,当编译器要在栈上分配内存,会去检查类的析构函数,如果析构函数是不可访问的,就不会分配内存了,这样这个类就无法在栈上生成对象。
55.如何定义一个只能在栈上生成对象的类?
将new,delete操作符重载为私有的。
在堆上生成对象,必须要使用new操作符,如果new被重载为私有的,就无法在堆上申请内存 。
56.shared_ptr是什么?
多个指针共享一个对象,使用计数器记录指向该对象的指针数量,当最后一个指针也不再指向该对象(也就是计数器为0时),自动销毁该对象。
57.weak_ptr是什么?
weak_ptr是为了解决shared_ptr的循环引用问题(两个已经不再被使用的对象互相有成员指针指向对方,导致这两个对象无法被释放),定义对象时用shared_ptr,使用对象时用weak_ptr。
weak_ptr共享但不拥有一个对象,当最后一个指向该对象的shared_ptr不再指向该对象,所有的weak_ptr自动为空。
58.unique_ptr是什么?
unique_ptr确保一个对象在同一时刻只被一个指针拥有。当unique_ptr超出作用域或者被删除或者指向其他对象时,它原先所指向的对象自动销毁。
可以解决内存泄露的问题(忘记delete对象)
59.强制类型转换运算符有哪些?作用分别是什么?
1) static_cast:
一般用于数值类型之间的互相转换
进行基类与派生类转换时,从派生类转到基类是安全的,从基类转到派生类是不安全的,因为没有运行时动态类型检查
2) dynamic_cast:
会进行动态类型检查,所以类层次之间的转换都是安全的
如果类型转换失败,就会抛出bad_cast异常
3) const_cast:
去掉类型中的const、volatile特性
4) reinterpret_cast:
按位进行强制转换,风险高
可以将任何指针转换成其他任何指针类型
60.typeid是什么?typeinfo什么?
typeid(expression)允许在运行时确定表达式的类型,返回一个typeinfo对象的引用,只能获取对象的实际类型
typeinfo类描述编译器在运行时生成的类型信息,一般是使用==进行判断类型是否相等