【游戏客户端面试题干货】-- 2021年度最新游戏客户端面试干货( C++篇 )

本文精选C++面试核心知识点,涵盖面向对象特性、重载、结构体、类、继承、虚函数等内容,辅以生动实例解析,助你轻松应对C++技术面试。

【游戏客户端面试题干货】-- 2021年度最新游戏客户端面试干货( C++篇 )

 

  大家好,我是Lampard~~

  经过春招一番艰苦奋战之后,我终于是进入了心仪的公司。

  今天给大家分享一下我在之前精心准备的一套面试知识。

 

  今天和大家分享的是C++的面试题

  本篇博客是结合博主自身遇到的问题以及csdn中近3年的10篇高赞【c++面试题博客】综合写出,有一些我感兴趣的知识点会单独写一篇博客详细分析,大家可以通过链接跳转阅读,本人亲测80%的c++相关题目都是围绕着我总结出来的知识点提出的 。最后祝大家疯狂收割offer,通过自己的努力摆脱生活的苟且,走向诗和远方~

 

一. 面向对象特性:多态,继承,封装

1. 什么是面向对象(OOP)?面向对象的意义?

Object Oriented Programming, 面向对象是一种对现实世界理解和抽象的方法、通过将需求要素转化为对象进行问题处理的一种思想。其核心思想是数据抽象、继承和动态绑定(多态)。
面向对象的意义在于:将日常生活中习惯的思维方式引入程序设计中;将需求中的概念直观的映射到解决方案中;以模块为中心构建可复用的软件系统;提高软件产品的可维护性和可扩展性。

2. 解释下封装、继承和多态?

我们用经典三段论:what,why,how来解决这个问题

(1) 封装

what :封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的黑箱中。隐藏对象的属性和实现的细节,仅对外公开接口。

why:封装的意义有两个,对外在于简化编程使用者不需要了解具体的实现细节,只需要知道如何调用,从而做到模块之间高内聚(把逻辑都封装起来),低耦合(模块之间不需要相互依赖,程序员不需要了解每个模块的实现过程)对内在于保护代码(数据),避免止代码(数据)被我们无意中破坏

how:基本要求是把所有的成员变量(对象的属性)私有化。仅对外提供实现功能的接口。

(2) 继承

what 当两个类具有大量相同的特征(在代码中表现为属性大多想同)时,为了避免代码的重复编写造成冗余,以及方便对共同特性进行修改,从而实现的一种机制。目的让代码变得可重用和易拓展

why:继承的意义也有两个,可重用:可以重复使用代码,降低冗余,易拓展:方便对共同特性(基类)进行修改

how:  子类继承父类所有,只是访问受约束(public,protected,private)。

(3) 多态

what:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。在代码方面就是对接口的复用,一个接口多种实现。

why:  程序的可扩展性及可维护性增强。C++的虚函数是很好的例子,虚函数允许子类重新定义成员函数。这样子容易根据不同的子类对象产生不同的函数特性。

how:  C++中,实现多态具体体现在运行和编译两个方面:在程序运行时的多态性通过抽象类和虚函数来体现(运行才知道谁重写);在程序编译时多态性体现在函数和运算符的重载上(在编译的时候就知道实现多态的内容);

 

二. 重载(overload)

上文提及到,重载是c++在编译时展现多态性的一个操作。那么究竟什么是重载呢?

重载:是指允许存在多个同名函数,而这些函数的参数不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。目的是简化编程的工作以及提高代码的可读性。

 举个例子:

那么c++是如何识别这些同名的函数的呢?其实在编译的时候,c++就睡把这个函数定义为类似_addNum_int_int 和 _addNum_int_int_int的结构,编译器会根据参数的数量和类型找到需要执行的函数

重载overload和重写override(或者说覆盖)的区别:

提到重载,就会有一个老生常谈的问题,重载和重写的区别是什么呢?

(1)重载:重载翻译自overload,是指同一可访问区内被声明的几个具有不同参数列表(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型。
(2)重写:重写翻译自override,是指派生类中存在重新定义的函数。其函数名,参数列表,返回值类型,所有都必须同基类中被重写的函数一致,只有函数体不同。

 

三. 结构,联合,枚举

结构struct:

结构其实没什么好说的,我们早在学C的时候就已经接触过,定义一个结构体的关键字是struct。所以咱们还是直接举例子吧:

我们可以直接向node1一样声明一个结构体对象,也可以像node2那样声明一个结构体指针。它们的取成员的方式一个是使用.另一个是使用->

联合union:

联合的定义和声明方式和结构体没差,只是关键字改为union。那么它和结构体的区别在于,联合只能对其那么多个成员属性的其中一个赋值,而结构体很明显是每一个成员都可以赋值的。举一个不恰当的例子,你有多个异性好友,但是只能选择其中一个作为女朋友,把你的真爱交给她。但是如果你不信邪,我要把真爱交给两个人怎么办,那么很遗憾,之前的女朋友就会变成前女友不会再理你了。

union girls {
	string xiaohua;    // 小花
	string xiaocui;    // 小翠
	string xiaoting;   // 小婷
	girls() {};
	~girls() {};
};

int main() {
	girls girlFriend;
	girlFriend.xiaohua = "love";
	cout << girlFriend.xiaohua << endl;    // love
	girlFriend.xiaocui = "love";
	cout << girlFriend.xiaohua << endl;    // 乱码
	cout << girlFriend.xiaocui << endl;    // love
}

在lua和c进行交互时的数据就是使用联合来进行存储的

对lua和c/c++交互感兴趣的同学可以看一下我的这一篇博客:【lua_stack】

枚举enum:

枚举是一个有趣的类型,它能够帮助我们对一些变量进行限制并且使其变得可读。声明枚举的关键字时enum。

举个例子:

我们可以看到,无论是在定义还是在赋值的时候,我们都没有加"",说明它们并不是一个字符串,当我们把它输出来的时候,其实枚举里面的数据是从0开始记录的数字。

 

四. 类

c++和c的最大区别就是,c++编程思想是面向对象而c的编程思想是面向过程。而面向对象这个对象,在代码中就是封装起来的一个个类了。

class和struct的区别:

上文提到了结构体,其实结构体和类没太大不同,都会有构造函数,析构函数,成员变量。它们的区别是结构体中的变量默认作用域是public的,而类中的变量默认作用域是private。

new辆小车车:

虽然在现实中我们唯唯诺诺,但是在编程世界还不是想new什么就new什么嘛。这不直接来辆小车。

这样子我们就在类中定义了一个含有名字和汽油量gas的小车,然后还有一个run函数。每次运行减少一升油。但是我们这种写法,直接在类中定义函数确实可以,但是如果方法,变量比较多岂不是要写很长很长,这样不好读。所以我们可以换另外一种写法,在类中只定义函数头,然后在下文中,再用类解析符::声明这个函数。

再往下我们还可以把声明和定义写在.h函数和.cpp函数中。

// Car.h
#include <iostream>
#include <string>
using namespace std;

class Car {
public:
	string name;
	int gas = 100;

	void run();
	void addGas(int num);
};

// Car.cpp
#include "Car.h"

void Car::run() {
	gas--;
}

void Car::addGas(int num) {
	gas = gas + num;
}

// test.cpp
#include <iostream>
#include <string>
#include "Car.h"
using namespace std;

int main() {
	Car* car = new Car();
	cout << car->gas << endl;
	car->run();
	cout << car->gas << endl;
	car->run();
	cout << car->gas << endl;

	car->addGas(100);
	cout << car->gas << endl;
}

测试结果是一样的:

 

五.构造器和析构器

构造器和析构器大家都不陌生。C++支持我们写出一个创建或者销毁一个对象时所调用的方法。我们在new创建一个类的时候,就会调用对象的构造器,在delete的时候就会调用对象的析构器,清理内存。如果我们没有显示的定义一个构造器函数的话,那么就会调用默认构造函数。在C++中构造器没有返回值,名字和类相同。析构器同样没有返回值,名字和~+类的名字。

我们给Car设置一个构造函数和析构函数:

Car::Car() {
	cout << "我构造啦!!!" << endl;
	gas = 100;
	name = "BBA";
}

Car::~Car() {
	cout << "我析构啦!!!" << endl;
}

然而我们打印日志会发现:

怎么好像没有调用到析构函数 ? 不是的,是因为要等main函数返回了,销毁main函数的栈桢时才会调用析构函数的(可能会成为考点噢)。

构造函数可以有参数,利用函数重载的特性初始化属性值:

Car::Car(string carName, int gasNum) {
	cout << "我初始化啦!!!" << endl;
	gas = gasNum;
	name = carName;
}

 

六.继承

what 当两个类具有大量相同的特征(在代码中表现为属性大多想同)时,为了避免代码的重复编写造成冗余,以及方便对共同特性进行修改,从而实现的一种机制。目的让代码变得可重用和易拓展

why:继承的意义也有两个,可重用:可以重复使用代码,降低冗余,易拓展:方便对共同特性(基类)进行修改

how:  子类继承父类所有,只是访问受约束(public,protected,private),限制如下。

public,protected,private

公有继承(public) :公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态(public的话大家都可以访问,protected就需要子类和友元类才能够访问),而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问。
私有继承(private) :私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。
保护继承(protected) :保护继承的特点是基类的
所有公有成员和保护成员都成为派生类的保护成员(非子类或者友元函数就别想访问了),并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。

什么是友元关系呢?我们可以在一个类中任意一个地方是声明friend class XXX,这样子类中的所有属性都可以被该类访问。可以说友元关系比起子类更亲切,连private都能访问,而子类最多访问到protected

 

 C++的继承使用:(冒号)实现,举个例子,我们写一个动物继承:

class Animal {
public:
	void eat();
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lampard杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值