没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
概念问题
C++/数据结构
1、 简述你对“面向对象”和“面向过程”编程思想的认识与思考
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调
用就可以了。
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在
整个解决问题的步骤中的行为。
例如五子棋,面向过程的设计思路就是首先分析问题的步骤:1、开始游戏,2、黑子先走,3、绘制画面,4、判
断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤 2,9、输出最后结果。把上面每个步骤用分别
的函数来实现,问题就解决了。
而面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为 1、黑白双方,这两方的行为是一模一样
的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。第一类对象(玩家对象)负责接
受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的 i 变化就要负责在屏幕上
面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。
可以明显地看出,面向对象是以功能来划分问题,而不是步骤。同样是绘制棋局,这样的行为在面向过程的设计
中分散在了总多步骤中,很可能出现不同的绘制版本,因为通常设计人员会考虑到实际情况进行各种各样的简
化。而面向对象的设计中,绘图只可能在棋盘对象中出现,从而保证了绘图的统一。
功能上的统一保证了面向对象设计的可扩展性。比如我要加入悔棋的功能,如果要改动面向过程的设计,那么从
输入到判断到显示这一连串的步骤都要改动,甚至步骤之间的循序都要进行大规模调整。如果是面向对象的话,
只用改动棋盘对象就行了,棋盘系统保存了黑白双方的棋谱,简单回溯就可以了,而显示和规则判断则不用顾
及,同时整个对对象功能的调用顺序都没有变化,改动只是局部的。
再比如我要把这个五子棋游戏改为围棋游戏,如果你是面向过程设计,那么五子棋的规则就分布在了你的程序的
每一个角落,要改动还不如重写。但是如果你当初就是面向对象的设计,那么你只用改动规则对象就可以了,五
子棋和围棋的区别不就是规则吗?(当然棋盘大小好像也不一样,但是你会觉得这是一个难题吗?直接在棋盘对
象中进行一番小改动就可以了。)而下棋的大致步骤从面向对象的角度来看没有任何变化。
当然,要达到改动只是局部的需要设计的人有足够的经验,使用对象不能保证你的程序就是面向对象,初学者或
者很蹩脚的程序员很可能以面向对象之虚而行面向过程之实,这样设计出来的所谓面向对象的程序很难有良好的
可移植性和可扩展性。
2、 ADT 是什么?简述你对“数据抽象”和“信息隐藏”的认识
抽象数据类型(Abstract Data Type 简称 ADT)是指一个数学模型以及定义在此数学模型上的一组操作。抽象数据类
型需要通过固有数据类型(高级编程语言中已实现的数据类型)来实现。抽象数据类型是与表示无关的数据类型,
是一个数据模型及定义在该模型上的一组运算。对一个抽象数据类型进行定义时,必须给出它的名字及各运算的运
算符名,即函数名,并且规定这些函数的参数性质。一旦定义了一个抽象数据类型及具体实现,程序设计中就可以
像使用基本数据类型那样,十分方便地使用抽象数据类型。
抽象数据类型通过类(class)实现
程序设计语言对抽象数据类型的支持是指允许用户自定义具有如下特征的数据类型:
1. 模块封装:The representation of, and operations on, objects of the type are defined in a single
syntactic unit
2. 信息隐蔽:The representation of objects of the type is hidden from the program units that use these
objects, so the only operations possible are those provided in the type's definition
3、const 和 static 有什么作用?
const 是一个 C 和 C++语言的关键字,它限定一个变量不允许被改变,即只读。使用 const 在一定程
度上可以提高程序的安全性和可靠性,也便于实现对此进行优化(如把只读对象放入 ROM 中)。const
作为类型限定符,是类型的一部分。
静态变量(Static Variable)在计算机编程领域指在程序执行前系统就为之静态分配(也即在运行时中不
再改变分配情况)存储空间的一类变量。与之相对应的是在运行时只暂时存在的自动变量(即局部变量)
与以动态分配方式获取存储空间的一些对象,其中自动变量的存储空间在调用栈上分配与释放。
初始化为非零值的静态分配数据和全局数据存在数据段中,运行相同程序的每个进程都有自己的数据段。
初始化为零值的静态分配数据和全局数据存放在进程的 BSS 区域内。
BSS 段:
BSS 段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS 是英文
Block Started by Symbol 的简称。BSS 段属于静态内存分配。
是“Block Started bySymbol”的缩写,意为“以符号开始的块”。
BSS 是 Unix 链接器产生的未初始化数据段。其他的段分别是包含程序代码的“text”
段和包含已初始化数据的“data”段。BSS 段的变量只有名称和大小却没有值。此名后来
被许多文件格式使用,包括 PE。“以符号开始的块”指的是编译器处理未初始化数据的地
方。BSS 节不包含任何数据,只是简单的维护开始和结束的地址,以便内存区能在运行
时被有效地清零。BSS 节在应用程序的二进制映象文件中并不存在。
数据段:
数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静
态内存分配。静态变量存放在 data 段中
代码段:
代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的
大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在
代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。代码段是存放了程序代码的数据,假如机器
中有数个进程运行相同的一个程序,那么它们就可以使用同一个代码段。
堆(heap)
:堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调
用 malloc 等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用 free 等函数释放内存时,
被释放的内存从堆中被剔除(堆被缩减)
栈(stack)
:栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但
不包括 static 声明的变量,static 意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入
发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈
特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
4、友元关系的利与弊
如果将一个函数或一个类声明为另一个类的友元,那么它就可以直接存取这个类对象中的各种数据,而不必在
意这些数据的封装级别,即无论是 private 的,protected 的,还是 public 的,有钱同使,有难同当。
关于友元利弊的分析: 面向对象程序设计的一个基本原则是封装性和信息隐蔽,而友元却可以访问其他类中的私
有成员,不能不说这是对封装原则的一个小的破坏。但是它能有助于数据共享,能提高程序的效率,在使用友元时,
要注意到它的副作用,不要过多地使用友元,只有在使用它能使程序精炼,并能大大提高程序的效率时才用友元。
为什么有些操作符重载(<<, >>)必须要用友元函数而不能用成员函数?
如果是重载双目操作符(即为类的成员函数),就只要设置一个参数作为右侧运算量,而
左侧运算量就是对象本身。。。。。。
而 >> 或<< 左侧运算量是 cin 或 cout 而不是对象本身,所以不满足后面一点。。。。。。。。
就只能申明为友元函数了。。。
5、C++多态的实现
1. 用 virtual 关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数。
2. 存在虚函数的类都有一个一维的虚函数表叫做虚表。类的对象有一个指向虚表开始的虚指针。虚表是和类对应的,
虚表指针是和对象对应的。
3. 多态性是一个接口多种实现,是面向对象的核心。分为类的多态性和函数的多态性。
4. 多态用虚函数来实现,结合动态绑定。
5. 纯虚函数是虚函数再加上= 0。
6. 抽象类是指包括至少一个纯虚函数的类。
http://blog.csdn.net/tujiaw/article/details/6753498
构造函数顺序:
基类构造函数派生类构造函数
前面输出的结果是因为编译器在编译的时候,就已经确定了对象调用的函数的地址,要解决这个问题就要使用迟绑
定(late binding)技术。当编译器使用迟绑定时,就会在运行时再去确定对象的类型以及正确的调用函数。而要
让编译器采用迟绑定,就要在基类中声明函数时使用 virtual 关键字(注意,这是必须的,很多学员就是因为没有使
用虚函数而写出很多错误的例子),这样的函数我们称为虚函数。一旦某个函数在基类中声明为 virtual,那么在所有
的派生类中该函数都是 virtual,而不需要再显式地声明为 virtual。
前面输出的结果是因为编译器在编译的时候,就已经确定了对象调用的函数的地址,要解决这个问题就要使用迟绑
定(late binding)技术。当编译器使用迟绑定时,就会在运行时再去确定对象的类型以及正确的调用函数。而要让
编译器采用迟绑定,就要在基类中声明函数时使用 virtual 关键字(注意,这是必须的,很多学员就是因为没有使用
虚函数而写出很多错误的例子),这样的函数我们称为虚函数。一旦某个函数在基类中声明为 virtual,那么在所有的
派生类中该函数都是 virtual,而不需要再显式地声明为 virtual。
编译器在编译的时候,发现基类中有虚函数,此时编译器会为每个包含虚函数的类创建一个虚表(即 vtable),该
表是一个一维数组,在这个数组中存放每个虚函数的地址。
那么如何定位虚表呢?编译器另外还为每个类的对象提供了一个虚表指针(即 vptr),这个指针指向了对象所属
类的虚表。在程序运行时,根据对象的类型去初始化 vptr,从而让 vptr 正确的指向所属类的虚表,从而在调用虚函
数时,就能够找到正确的函数。对于例 1-2 的程序,由于 pAn 实际指向的对象类型是 fish,因此 vptr 指向的 fish 类
的 vtable,当调用 pAn->breathe()时,根据虚表中的函数地址找到的就是 fish 类的 breathe()函数。
那么虚表指针在什么时候,或者说在什么地方初始化呢?
答案是在构造函数中进行虚表的创建和虚表指针的初始化。还记得构造函数的调用顺序吗,在构造子类对象
时,要先调用父类的构造函数,此时编译器只“看到了”父类,并不知道后面是否后还有继承者,它初始化父类对象
的虚表指针,该虚表指针指向父类的虚表。当执行子类的构造函数时,子类对象的虚表指针被初始化,指向自身的
虚表。对于例 2-2 的程序来说,当 fish 类的 fh 对象构造完毕后,其内部的虚表指针也就被初始化为指向 fish 类的
虚表。在类型转换后,调用 pAn->breathe(),由于 pAn 实际指向的是 fish 类的对象,该对象内部的虚表指针指向的
是 fish 类的虚表,因此最终调用的是 fish 类的 breathe()函数。
要注意:对于虚函数调用来说,每一个对象内部都有一个虚表指针,该虚表指针被初始化为本类的虚表。所以在程
序中,不管你的对象类型如何转换,但该对象内部的虚表指针是固定的,所以呢,才能实现动态的对象函数调用,
这就是 C++多态性实现的原理。
6、STL 是什么?组成部分和核心作用
标准模板库(英文:Standard Template Library,缩写:STL),是一个 C++软件库,也是 C++
标准程序库的一部分。其中包含 5 个组件,分别为算法、容器、迭代器、函数、适配器。容器即物之所
属;算法是解决问题的方式;迭代器是对容器的访问逻辑的抽象,是连接算法和容器的纽带,通过添加
了一种间接层的方式实现了容器和算法之间的独立。本文从应用的角度对 STL 的方方面面进行了简单的
介绍。
模板是 C++程序设计语言中的一个重要特征,而标准模板库正是基于此特征。标准模板库使得 C++
编程语言在有了同 Java 一样强大的类库的同时,保有了更大的可扩展性。
标准模板库于 1994 年 2 月年正式成为 ANSI/ISO C++的一部份,它的出现,促使 C++程序员的思维方式更朝向泛型编
程(generic program)发展。
7、阐述C++在什么情况下必须进行运算符重载。
?
8、 为什么说“继承是C++面向对象的一个主要特征之一”,请做一下简要说明。
?
9、 请说明函数模板(Function Template)和函数模板实例化(function-template specification)的区别和联
系。
函数模板实例化
在函数模板为每个类型时首先调用中,编译器创建一个实例化。 每个实例化是为该类型的该模板化功能的版本。 在中,此函数为类
型时,使用此实例化将调用。 如果您有几个相同的实例化,即使在不同的模块,因此,只有该实例化的一个副本在可执行文件将结
果。
函数参数将所有参数的函数模板允许和参数,对该参数不依赖于模板参数的位置。
函数模板可以通过声明与特定类型的模板显式实例化作为参数。
C++中提供了函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来
代表,这个通用函数就成为函数模板。使用模板的好处就是对于那些函数体相同的函数都可以用这个模板来代
替,而不必去定义每个具体的函数去实现。下面通过一个简单的具体例子(比较两个数的大小)来说明:
#include <iostream>
using namespace std;
template<class T> //模板声明,T 为类型参数
T Max(T a, T b) //定义一个通用函数,用 T 作虚拟的类型名
{
if (a>b)
{
return a;
}
else
return b;
}
剩余32页未读,继续阅读
资源评论
- 追光者♂2022-05-22比较乱,不是很好用。
- qq_375398772019-03-25挺好的有用
- li_jeremy2022-03-10整理的有点乱啊xd
- 公众号:程序员之路2019-03-28挺好用的,谢谢
xxr233
- 粉丝: 13
- 资源: 1
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功