C++期末复习——简答题部分
C++期末简答题汇总(往年)
大部分问题的答案在软件学院C++相关文章里应该都能找到答案,这里做一个合订本
C++历史
?
C和C++的关系
- C++完全包含C语言成分,C++支持C所支持的全部编程技巧(C的超集);同时C++还添加了OOP支持
- 任何C程序都能被C++用基本相同的方法编写,并具备相同的运行效率和空间
- C++还引入了重载、内联函数、异常处理等功能,对C中的过程化控制及其功能进行了扩充
- C++由以下4部分有机组成
- C
- OOP
- STL
- Inside-Model
表达式的值有哪些因素决定?表达式存在副作用吗
- 表达式指由操作数、操作符和标点符号(比如逗号运算符)组成的序列,代表一个计算过程
- 表达式的值受操作符、操作数、优先级、结合性、求值次序、副作用、短路求值和类型转换(隐式or显式)影响
- 副作用:改变程序状态(即可能改变操作数或其他一些变量的值)
C++多态类型
- 静态多态
- 一名多用(函数重载、操作符重载)
- 模板编程(template)/ 泛型
- 动态多态
- 虚函数
解释指针类型和引用类型的差别
- 引用类型与指针类型都可以实现通过一个变量访问另一个变量,但访问的语法形式不同:引用采用直接访问形式,而指针采用间接访问形式
- 引用被创建是必须初始化(即必须绑定到变量上),而指针可以在任何时候初始化
- 不能有空引用,引用必须与合法变量绑定;但可以有空指针
- 一旦引用被初始化就不能改变绑定的变量,而指针可以随时改变指向的变量
- 从2 ~ 4可以看出引用比指针安全
传参时引用类型的实参是一个变量,而指针参数的实参是一个变量的地址(这条感觉怪怪的,难道指针就不是变量了吗?)
C++中继承与虚继承的差异
- 普通继承在面对多继承时可能会引入名冲突问题,每个继承路径都有自己的基类实例,而虚继承可以解决名冲突问题(形成一个菱形继承图“格”)
- 因为虚继承并没有真的继承基类的成员,而是生成了一个指向基类的指针,因此不会有名冲突问题(基类实际上只有一份,被所有虚继承的派生类共用;相当于虚基类被合并,只有一个副本)
- 虚继承的基类无法用
static_cast<>()
转成派生类 - 虚继承可能带来额外的性能开销
- 虚基类的构造函数优先于非虚基类的构造函数被调用
为什么实现两个版本的下标运算符重载
两个版本是一个带const
,一个不带
class string { |
需要分别对应两种*this
指针,const T* this
和T* this
且若某个调用产生了两个候选函数,而一个有const
一个没有,若调用处不修改对象,则优先选择带有const
的函数,因为const
保证不修改,选const
函数使得更多代码可以在const
上下文中使用,避免非const
函数隐式修改。
请简述右值引用与左值引用的异同
相同点:
- 本质都是引用
- 语法相似,左值引用是
&
,右值引用是&&
- 传递效率都很高,无论是左值还是右值引用都避免了传值时的值拷贝
- 两者都可以作为函数参数,允许直接操作被引用的对象
不同点:
- 左值引用引用的是左值对象(即有名字、可持久存在的对象),而右值引用引用的是右值对象(即无名字、临时的对象,通常是表达式的结果)
- 左值是可以取地址的实体,右值通常不能取地址
- 左值引用常常用于需要对现有变量进行修改或访问的地方,而右值引用往往用于临时对象操作,比如移动语义(可以提高效率,避免不必要拷贝)
- 左值引用提出绑定到长生命周期对象上,被引用的对象必须是有效的;右值引用通常绑定到短生命周期的临时对象上,右值引用延长了右值对象的生命周期(只要右值引用还在,该对象就还能访问)
- 右值引用可以用于移动语义,高效转移资源
- 在函数重载时左值引用和右值引用是不同的参数类型
Lambda表达式的作用并比较它与重载了函数调用操作符的函数对象的差别
- lambda表达式作为匿名函数使用,避免了一些轻量函数使用时还要定义,避免繁琐步骤,更加简洁
- lambda表达式不需要显式指明函数返回类型,函数对象需要
- lambda表达式不需要先声明再使用(即用即定义),函数对象需要
- lambda表达式实际上是用函数对象实现的(编译器生成一个匿名函数对象类,lambda表达式返回其实例,为右值)
简述C与C++混合编程时需要注意的问题
- C++是C的超集,而C不支持OOP,不要在混合编程中出现
class
等面向对象关键字 - 调C库函数时附加关键字
extern C
- 注意函数重载,C不支持
- 注意求值顺序和副作用
- 内存分配差异(new/malloc, delete/free)
- 内存占用差异
内联函数的作用?随意使用的问题?阐述合理使用的建议
- 作用:
- 提高可读性:编译器眼中没有函数但程序员不是,可以提高代码的可读性
- 提高效率:编译器不再需要进行函数调用,而是直接顺序地执行等价代码,避免了函数调用的时间开销
- 问题:
- 增大目标代码
- 病态的换页
- 降低指令快取装置的命中率
- 建议:
- 适合于频率高、简单的小段代码
- 不要滥用
inline
- 不要内联复杂的控制逻辑
- 不能内联递归
- 把内联函数扔头文件里
C++关键字const的几种使用方法,并给出示例
- 修饰基本数据类型,表示常量
const int a = 1; |
- 修饰指针,两种,或者说三种
int a = 114; |
- 修饰(成员)函数
int f(const& int); // 参数是常量 |
- 修饰对象
但要保证对象的所有变量都能在声明对象时被初始化(要么内部实现声明时初始化,要么构造函数实现)
class A { |
或
class A { |
什么是纯虚函数、虚函数和非虚函数?合理定义三种成员函数的基本原则是什么?请给出一个你认为合理定义的实例
- 纯虚函数
- 只有函数接口会被继承
- 派生类必须继承函数接口
- 派生类必须提供实现代码
- 一般虚函数
- 函数的接口及缺省的实现代码都会被继承
- 子类必须继承函数接口
- 可以缺省实现代码
- 非虚函数
- 函数的代码及其实现代码都会被继承
- 必须同时继承接口和实现代码,无法重写以提供自己的实现
原则:
- 类的成员函数才能是虚函数
- 静态成员函数不能是虚函数
- 内联不能是虚函数
- 构造不能是虚函数
- 析构往往是虚函数
C++程序设计中,可以利用析构函数防止资源泄露,请给出模板auto_ptr的基本定义及使用实例
template <typename T> |
请阐述OOP中引入构造函数机制的原因,并请给出控制一个类创建实例个数的手段(举例)
单例模式、或者使用一个静态成员变量记录实例化的类数量,超过则拒绝实例化。
具体略
何为引用?其主要作用是什么?何时需要将一个函数的返回值类型定义为引用类型?如果随意将函数的返回值类型定义为引用类型会有什么危害?
- 定义:C++通过引用将一个左值和已有的变量绑定在一起(称为引用),引用和其绑定的变量使用相同的内存,被等价的修改,相当于变量的一个别名
- 作用:主要用于函数传参时代替指针,形参声明引用,实参传引用,可以在函数内部修改外部变量(通过引用)
- 什么时候返回:当希望提高效率避免对象值拷贝时,返回引用
- 危害:若返回值是引用,不能把局部变量返回,这是UB
你认为最有价值的C++程序设计应该遵守的5条规则,并简明分析其意义所在
略
C++赋予一个空类哪些成员函数
class Empty { |
更详细的见C++面向对象编程基础
define和template的区别
- define不做类型检查,直接展开,template会类型检查
- define的作用范围是全局的,除非用
#undef
结束定义 - 模板很好的支持代码复用
面向对象程序设计的特点
封装、继承、多态,通过消息传递、对象间分工协作实现程序运转
什么是ADT?试以时间类型为例简要描述
Abstract Data Type 抽象数据类型
结构化编程需要关注抽象数据类型、联系、优先级、类型转换(强制、隐式、溢出?)、求值顺序、副作用
描述略
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 (๑>ᴗ<๑)!
评论