面试之C++(篇一:类)

目录

1.C与C++的区别

2.面向对象三大特征(封装、继承、多态)

3.类的访问控制权限private、protected、public

4.重写、重载、重定义的区别

5.虚函数与纯虚函数

6.虚函数的实现原理

7.编译时多态与运行时多态

8.友元函数

9.简述构造函数与析构函数的作用

10.构造函数与析构函数可以设置为virtual吗?

11.析构函数中为什么不能delete该类对象

12.构造函数和析构函数能够被重载吗?

13.拷贝构造与赋值构造的区别

14.类构造函数的列表初始化的优势

15.构造函数列表初始化的顺序

16.空类占用的内存大小

17.浅拷贝与深拷贝的区别

18.emplicit和implicit的区别

19.class与struct的区别


1.C与C++的区别

(1)C是面向过程的结构化编程语言,更加注重逻辑过程,根据输入进行运算并输出;C++是面向对象的语言,更加注重对象模型的构建,使得构建的模型契合问题域,通过定义模型方法来解决问题。

(2)C++是C的超集。C++中引入了类、模板、封装、继承、多态、设计模式、函数重载、STL等。

(3)C更适用于代码体积小,效率要求较高的场景;C++更适用于上层的、更加复杂且需要多次进行迭代的场景。(例如:Linux的内核是用C进行编写的)

 

2.面向对象三大特征(封装、继承、多态)

(1)封装(数据隐藏、代码模块化):构建对象模型——类,将数据和操作数据的方法封装在类中,通过设置访问标志实现不同用户对不同数据的访问权限控制,避免一些不当操作错误或是意外修改了数据。

(2)继承(代码复用):父类派生子类,子类继承了父类的部分属性及方法(protected、public),并在原有的基础上进行扩展或者重写,提高了代码的复用性。

(3)多态(接口重用):子类重写父类的虚函数,实现同种方法不同实例对象的不同处理(子类对象实例化父类类型)。

 

3.类的访问控制权限private、protected、public

(1)private:只有该类的成员可以访问

(2)protected:只有该类以及该类的派生类可以访问

(3)public:该类以及类外都可以访问

 

4.重写、重载、重定义的区别

(1)重写(覆盖):发生在父类和子类之间,子类重写父类的虚函数,可以不加virtual,重写的函数名、返回类型以及参数列表完全相同,只有函数体不同。

(2)重载:一般发生在同一作用域中,重载的函数函数名相同,参数列表不同(类型、数量、顺序至少一种不同),与返回类型无关。

(3)重定义(隐藏):发生在父类和子类之间,子类重定义父类的非虚函数,函数名相同,与返回类型和参数列表无关。

 

5.虚函数与纯虚函数

(1)声明格式不同。以无返回类型为例,虚函数为virtual void func(),纯虚函数为virtual void func() = 0。

(2)纯虚函数只能声明,不能定义,声明了纯虚函数的类被称为抽象类,不能实例化对象,只能进行派生,且继承了抽象类的子类必须重写纯虚函数。

(从上述两条可以看出,虚函数与纯虚函数的功能相似,为何还要引入纯虚函数呢?因为在一些情况下实例化基类对象是不合理的,因此通过定义声明了纯虚函数的抽象类来满足这一实际场景。)

 

6.虚函数的实现原理

(1)每个包含虚函数的类及其派生类都有一个虚函数表,一个类只能有一个虚函数表,这个表由该类的所有对象共享。

(2)虚函数表是一个指针数组,其元素是该类虚函数的指针,存储顺序由虚函数的声明顺序决定,虚函数表是在编译阶段构建的。

(3)声明了虚函数的类对象都有一个虚表指针,指向该类的虚函数表。

 

7.编译时多态与运行时多态

(1)编译时多态是由重载实现的

(2)运行时多态是由重写实现的

 

8.友元函数

(1)在类内用friend关键字声明的一个函数,其定义一般在类外。

(2)其意义是让非成员函数可以访问类的protected和private成员。

(3)缺点是无视了protected和private的权限控制,破坏了类的封装特性,因此慎用。

 

9.简述构造函数与析构函数的作用

(1)构造函数申请内存,创建对象本身,不能设置为虚函数。

(2)析构函数销毁对象,释放内存,一般多设置为虚函数。

 

10.构造函数与析构函数可以设置为virtual吗?

(1)构造函数不能设置为virtual,因为虚函数涉及到了虚函数表以及虚表指针,这两者都需要申请内存,而类中申请内存这一功能是由构造函数完成的。

(2)析构函数一般会设置为virtual,为的是子类在调用其析构函数时能够正确释放父类申请的内存。因此基类有派生类时,都必须将基类的析构函数声明为virtual。而若该类不用进行派生时则无需将析构函数设置为virtual,因为设置为virtual可能会因为虚函数表和虚表指针占用额外的内存,类的默认析构函数就是非虚的。

 

11.析构函数中为什么不能delete该类对象

C++的delete会自动调用该类的析构函数,因此调用一次析构函数相当于调用多次析构导致出错。

 

12.构造函数和析构函数能够被重载吗?

(1)构造函数可以被重载。一个类的构造函数可以有多个,无返回类型但是可以有不同的参数列表。

(2)析构函数不能够被重载。一个类的析构函数只能有一个,且无返回类型,无参数。

 

13.拷贝构造与赋值构造的区别

(1)构造的形式不同

拷贝构造:A a; A b(a); A c(b);

赋值构造:A a; A b; a = b;

从上面两种形式可以看出,拷贝构造是将一个已初始化的对象来初始化另一个对象;赋值构造则是将两个都已经初始化的对象进行赋值操作。

(2)重载形式不同

拷贝构造:A(const A& a)

赋值构造:A& operator = (const A& a)

(3)拷贝构造函数的发生场景

  • 一个对象初始化另一个对象;
  • 一个对象以值传递的方式传入函数体;
  • 一个对象以值传递的形式作为函数返回;

 

14.类构造函数的列表初始化的优势

减小了多次调用构造函数带来的性能开销。

(1)编译器保证了类的所有成员对象在构造函数体之前完成了构造;

(2)通过构造函数体实现类成员的构造将调用两次构造函数;

(3)利用列表初始化使得成员在构造函数体执行前就完成了内存的申请及对象的初始化,只执行了一次拷贝构造。

 

15.构造函数列表初始化的顺序

根据类成员在类内的声明顺序进行初始化

 

16.空类占用的内存大小

1字节(标准规定)。为什么不为0?原因是空类也可以实例化对象,而实例化的对象如果不占用内存则无法进行调用,另外如果一个空类实例化了多个对象,不占用内存则无法进行区分。

 

17.浅拷贝与深拷贝的区别

(1)浅拷贝是拷贝得到的指针与被拷贝的指针指向相同的地址空间;

(2)深拷贝是申请一段地址空间,两个内存空间存储着相同的数据;

(类的构造函数默认是浅拷贝,当类中有指针成员时必须要重载拷贝构造函数,避免浅拷贝释放内存带来的内存泄漏问题)

 

18.emplicit和implicit的区别

(1)emplicit是显式声明,implicit是隐式声明,类的构造函数默认为隐式声明。

(2)通过在构造函数前加上emplicit关键字,避免类构造函数的隐式转换,emplicit只对只有一个参数的构造函数有效。

 

19.class与struct的区别

(1)class是C++中的类,struct是C中的结构体。

(2)默认访问权限不同。class默认是private成员,struct默认是public成员。

(3)默认继承权限不同。class默认是private继承,struct默认是public继承。

(注:这里的比较是C++中的class和C中的struct的区别,C++中class和struct没有区别)

 

下一篇:面试之C++(篇二:STL)

以上内容均是个人理解总结,若有错误欢迎指出!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值