C/C++面试八股题(一)
目录:
1.请说说操作符重载?哪些操作符不能重载?
2.在C++中重写、重载和隐藏的区别是什么?
3.请说明一下面向对象的三大特性。
4.什么是虚函数?虚函数存在哪?虚函数的优点有哪些?
5.虚函数如何实现多态性?
6.虚函数在子类中如何重新定义?
7.关于虚函数表的注意事项。
内容:
1.请说说操作符重载?哪些操作符不能重载?
操作符重载,就是把已经定义的、有一定功能的操作符进行重新定义,来完成更为细致具体的运算等功能。
在 C++中,当用户定义了类的对象时,两个对象之间是不能进行内置类型的操作符运算的,比如两个自定义类的对象相加,如果没有重载+运算符就会出错。但 C++允许用户把这些运算符添加到自己的类中以方便类对象之间的运算,就像内置类型的运算一样方便。
可以重载的运算符:
- 算数运算符
- 自增自减
- 比较运算
- 位运算
- 赋值运算
不能被重载的运算符:
- 成员选择操作符(.):无法改变点操作符的行为。点运算符“.”不能重载是为了保证访问成员的功能不能被改变
- sizeof:它是一个关键字,无法重载。
- typeid:它是一个运算符,无法重载。
- 条件运算符(?:):无法改变条件运算符的行为。条件运算符“?:”不能重载是因为如果能够重载,该运算符的本意是执行 exp2 和 exp3 中的一个,可是重载后,不能保证只执行了一个,还是说两个都能执行?亦或两条都不能执行?
- 展开操作符(::):它用于指定作用域,不能被重载。域解析符“::”不能重载是因为它只是在编译的时候进行域解析,而没有运算的参与进来。如果重载之后,“::”运算符有了新的语义,那会引起混淆。
2.在C++中重写、重载和隐藏的区别是什么?
重写(Override):
- 重写是指子类重新定义从父类继承的虚函数,使其具有不同的实现。
- 重写的函数签名(函数名、参数列表和返回类型)必须与被重写函数相同。
- 在运行时,根据具体的对象类型,调用的是子类重写的版本。例如,“// 父类 classA { public:virtual int fun (int a){} };// 子类 classB : public A { public:virtual int fun (int a) override {} }”。重写是父类和子类之间的垂直关系,在重写关系中,调用方法根据对象类型决定。
重载(Overloading):
- 函数名相同但参数列表(类型、个数、顺序)不同,返回值类型无要求
隐藏(Hiding):
- 隐藏是指在派生类中定义与父类具有相同名称的成员函数,使其隐藏父类中的同名函数。
- 隐藏函数与父类的函数没有多态性,只有通过对象的实际类型调用时才会调用相应的函数。举个例子:// 父类 classA { public:void fun (int a){ cout << "A 中的 fun 函数" << endl;} };// 子类 classB : public A { public:// 隐藏父类的 fun 函数 void fun (int a){ cout << "B 中的 fun 函数" << endl;} }”。总结,重写发生在不同的类之间且要求严格,重载发生在同一个类内,隐藏发生在不同类间
3.请说明一下面向对象的三大特性
面向对象编程的三大特性是封装、继承和多态
封装(Encapsulation):
- 封装是将数据和操作封装在一个单元(类)中的机制。对外部隐藏具体实现细节
- 通过封装,实现类的成员变量和成员函数作为一个整体进行管理和操作。
- 封装隐藏了数据的具体实现细节,提高安全性,提高可维护性。
- 访问修饰符如 private、public、protected 等限制对类成员的访问。
继承(Inheritance):
- 继承是通过创建派生类来扩展和重用已有类的机制。
- 继承是指一个类(子类)从另一个类(父类)继承属性和方法的过程。子类可以自定义新的属性和方法,也可以覆盖或扩展继承的父类的属性和方法。子类继承了父类的属性和方法,可以直接使用父类的成员,也可以对继承的父类方法进行重写。
- 继承的优势包括代码复用,创建类的层次结构使代码更有组织和易于理解,同时也是实现多态的基础。
多态(Polymorphism):
- 多态是指同一类型的对象,在不同情况下表现出不同的行为。
- 多态允许使用基类的指针或引用来引用派生类的对象,实现了多种形态的使用。
- 编译时多态使用函数重载和运算符重载;运行时多态通过虚函数实现(动态绑定)。
- 多态的优势包括灵活性和可扩展性,代码重用,提供统一接口使代码更加通用和可维护。
- 实现多态的三个必要条件为继承、重写、父类引用指向子类对象。
4.什么是虚函数?虚函数存在哪?虚函数的优点有哪些?
虚函数是在普通函数前面加了 virtual 关键字的成员函数,在某基类中声明为 virtual 并在一个或多个派生类中被重新定义,实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。
关于虚函数的存在位置,虚函数表是与类关联的,一个类只有一张虚函数表。虚函数和普通函数一样的,都是存在代码段的。
优点:
实现多态性:通过使用虚函数,可以创建一个统一接口,以便处理具有不同类型但具有相似功能和行为的对象。
简化代码逻辑:通过将通用操作放在基类中定义,并使用派生类覆盖特定功能,可以减少代码冗余并提高可维护性。
扩展性和灵活性:通过添加新的派生类并覆盖虚函数,可以轻松地扩展和修改现有的代码结构。
5.虚函数如何实现多态性?
虚函数是 C++ 中实现多态的重要机制。多态就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数,让父类的指针有 “多种形态”。
例:有基类 A 和派生类 B,A 中有虚函数 print,B 重写了这个函数。在主函数中,先创建 A 和 B 的对象,然后用 A * 类型的指针分别指向 A 和 B 的对象,调用 print 函数时,如果 A 的 print 不是虚函数,那么无论指针指向的是哪个对象,都只会调用 A 的 print 函数;但当 A 的 print 是虚函数时,根据指针实际指向的对象来调用相应的函数,即如果指针指向 B 的对象,就会调用 B 重写后的 print 函数,从而实现多态性。
6.虚函数在子类中如何重新定义?
当子类继承有虚函数的父类时,子类可以重新定义父类的虚函数。如果基类的成员函数设为 virtual,其派生类的相应函数也会自动变为虚函数。在重写虚函数时,子类中的函数名、函数类型、返回值类型、函数参数个数和类型都要与父类的虚函数相同,并根据子类的需要重新定义函数功能。
例:有一个父类 Shape,其中有虚函数 calcArea,子类 Circle 和 Rect 分别重写了这个函数来计算圆形和矩形的面积。子类在重写虚函数时,不一定要在函数声明前加上 virtual 关键字,但最好加上以便更清晰地看出这是虚函数。如果子类不重写虚函数,则它会继承父类的虚函数。
7.关于虚函数表的注意事项
- 每个含有虚函数的类都有一个虚函数表,表中存放着虚函数的地址。当通过基类指针或引用调用虚函数时,实际上是通过虚函数表来找到正确的函数地址进行调用。
- 虚函数表只有一份,而有多少个对象,就对应多少个虚函数表指针。
- 静态成员函数不能是虚函数,因为静态成员函数不受限与某个对象。
- inline 函数不能是虚函数,因为 inline 函数是不能在运行中动态确定其位置的,即使虚函数在类的内部定义,编译时,仍将其视为非 inline 的。
- 使用虚函数,系统要有一定的空间开销,当一个类带有虚函数时,编译器会为该类构造一个虚函数表,虚函数表在编译时候就已经生成了。它是一个指针数组,存放每个虚函数的入口地址。
声明:本人不是什么大佬,如有问题欢迎评论区或者私信我,很愿意跟大家一起探讨解决问题,共同一起进步。
后续还会继续更新,感谢大家支持。
#C/C++##面经##八股##牛客创作赏金赛##嵌入式#本人双飞本,校招上岸广和通。此专栏覆盖嵌入式常见面试题,有C/C++相关的知识,数据结构和算法也有嵌入式相关的知识,如操作系统、网络协议、硬件知识。本人也是校招过来的,大家底子甚至项目,可能都不错,但是在面试准备中常见八股可能准备不全。此专栏很适合新手学习基础也适合大佬备战复习,比较全面。最终希望各位友友们早日拿到心仪offer。也希望大家点点赞,收藏,送送小花。这是对我的肯定和鼓励。 持续更新中