一、简答题
1、简述你对“面向对象”和“面向过程”编程思想的理解和认识。
“面向过程”是一种以事件为中心的编程思想,就是分析出解决问题所需要的步骤,然后
用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。过程化编程强调
功能,以过程模块为中心,分层逐步展开设计。通常采用结构化程序设计,基本思路为:自
顶向下、逐步求精。
“面向对象”的编程思想就是把你需要解决的问题中的所有具体的东西,都看成一个个具
有属性和行为的对象,然后把所有具有相同性质的对象抽象成类,那些与问题无关的对象则
忽略。对象化编程强调分离抽象层次,以便让程序员分工,关心不同抽象层次中的细节,而
不用去关心不同抽象层次的联系,数据安全而隐蔽,不同抽象层次的职责分明。
2、ADT 是什么?简述你对“数据抽象”和“信息隐藏”的认识。
C++内部的数据类型包括基本类型和复合类型(数组、字符串、指针和结构),有表示
范围,只是用可以接受的方式表示实际概念。确定了一个类型就确定了计算机存储给类型所
需要的容量,确定了其表示范围,也确定了对该类型可以进行的操作。
抽象数据类型(Abstract Data Type),简称 ADT,是指一个数学模型以及定义在该模型
上的一组操作。
通常以以下格式定义:
ADT 抽象数据类型名{
数据对象:<数据对象的定义>
数据关系:<数据关系的定义>
基本操作:<基本操作的定义>
}
数据抽象:对具体事物描述的一个概括。通过数据抽象可以将数据类型的定义和它的实
现分开,使得只研究和使用它的结构而不用考虑它的实现细节成为可能。C++中的类就是一
种数据抽象,类是具有相同属性和服务的一组对象的集合。
信息隐藏:C++中的封装就是信息隐藏的一种,即尽可能的隐藏对象的内部细节,对外
形成一个边界,只保留有限的对外接口使之与外部反生关系。
3.编写语句说明枚举类型是如何定义和使用的。
枚举类型的声明形式如下
enum 枚举类型名 { 变量值列表 } ;
例如: enum weekday{ sun , mon , tue , wed , thu , fri , sta } ;
变量定义:enum weekday a , b , c = tue ; //也可以省略 enum
1)枚举元素具有默认值,他们依次是:0 , 1 , 2 , … , 例子中:sun 的值为 0 , mon 的值
为 1,tue 的值为 2,… ,sta 的值为 6 。
2)枚举元素按常量处理,不能进行赋值。
3)整数值也不能赋给枚举变量,如确实需要可进行强制类型转换。
4)枚举变量可以进行关系运算。
4.什么是逻辑错误?什么是语法错误?请举例说明。
逻辑错误:由于程序设计人员设计的算法有错或编写的程序有错,此时程序一般能够正
常运行,但是通知给系统的指令与解题的原意不相同,即出现了逻辑上的混乱。
例如:int a[5] = { 1 , 2 , 3 , 4 , 5} ;
for( int i = 0 ; i <= 0 ; i ++ )
cout << a[i] << endl ;
//发生数组越界
语法错误:违背了 C++语言的规定,不能生成可执行文件,主要是语句的结构或拼写中
存在的错误。
例如:for( int i = 0 , i < 10 , i ++) { }
//应该用“;”
5.控制语句有哪几种?请画出流程图或者 UML 图。
6.const 和 static 有什么作用?
const
(1) 可以定义 const 常量,具有不可变性,从而保护被修饰的东西,防止意外的修改,增强程
序的健壮性。
(2) 便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。
(3) 可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。同宏定义一
样,可以做到不变则已,一变都变!
(4) 可以节省空间,避免不必要的内存分配。const 定义的常量在程序运行过程中只有一份
拷贝,而#define 定义的常量在内存中有若干个拷贝。
(5) 提高了效率。
static
(1)类的静态数据成员:它属于类,是该类的所有对象所公有的,所共同维护的,只有
一份拷贝,只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样
可以提高时间效率。
在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静
态成员。
(2)在全局变量前,加上关键字 static 该变量就被定义成为了一个静态全局变量。
特点:
A、该变量在全局数据区分配内存。
B、初始化:如果不显式初始化,那么将被隐式初始化为 0。
C、访变量只在本源文件可见,严格的讲应该为定义之处开始到本文件结束。
在局部变量前加上 static 关键字时,就定义了静态局部变量。
特点:
A、该变量在全局数据区分配内存。
B、初始化:如果不显式初始化,那么将被隐式初始化为 0。
C、它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义
它的函数或语句块结束时,其作用域随之结束。
(3)静态函数(注意与类的静态成员函数区别)
定义:在函数的返回类型前加上 static 关键字,函数即被定义成静态函数。
特点:
A、静态函数只能在本源文件中使用(这是与普通函数区别)
B、主意事项:在文件作用域下声明的 inline 函数默认为 static 类型。
7.友元关系的利与弊
优点:通过友元,一个不同函数或另一个类中的成员函数可以访问类中的私有成员和保
护成员。c++中的友元为封装隐藏这堵不透明的墙开了一个小孔,外界可以通过这个小孔窥
视内部的秘密。
缺点:友元的正确使用能提高程序的运行效率,但同时也破坏了类的封装性和数据的隐
藏性,导致程序可维护性变差。
8.类作用域和文件作用域的区别?请详细说明。
类作用域:类定义作用域为包含类定义的花括号语句块,如果没有花括号语句块,则为
从类定义开始的全部代码空间。而类作用域范围更小,仅包括类定义内部和所有其成员函数
的定义体,类作用域中,类的成员函数对数据成员和其他成员函数具有无限制的访问权。
文件作用域是在所有函数定义之外说明的,其作用域从说明点开始,一直延伸到源文件结束。
文件作用域即为静态全局的。用static 修饰的全局数据和函数是文件作用域的。
类作用域包含于文件作用域。在类作用域如果声明了和文件作用域同名的标识符会屏蔽
全局作用域中的标示符。在类域中定义的变量不能使用 auto,register 和 extern 等修饰符,
只能用 static 修饰符,而定义的函数也不能用 extern 修饰符。
9.为什么说“继承是 C++面向对象的一个主要特征之一”,请作一下简要说明。
继承是一种联结类的层次模型, 层次结构的上层(或祖先类)是最具有通用性的, 而下层
部分,即后代则具有特殊性。类可以从它的祖先那里继承方法和成员变量,并且类可以修改类
或增加新的方法使之更符合特殊的需要。如果没有继承,类就缺了一块层次结构,代码重用
和数据共享就贯彻不到底;有了继承,就会有抽象编程中的多态问题,只有从机制内部真正
解决了多态表现问题,对象的数据封装、信息隐藏、代码重用等招数才能淋漓尽致地发挥。
对象的表现自如了,针对对象的抽象编程就能贯彻到底,才称得上是真正的面向对象。
10.如何声明和使用虚函数。说明它在多态性中的作用和意义。
声明:在基类中声明成员函数时在前面加上关键字 virtual 。
使用虚函数:在基类中将成员函数声明为虚函数,这样在派生类中重写该方法后,在使
用基类的指针或引用指向派生类对象时,就可以通过这个基类指针或引用访问到派生类的方
法。
C++中的多态可分为四类:重载多态、强制多态、包含多态和参数多态,其中包含多态
是研究类族中定义于不同类中的同名函数的多态行为,主要通过虚函数来实现。多态使得接
口与实现得到分离,要利用统一接口实现运行时多态一般需要动态绑定,而虚函数是动态绑
定的基础,就使得虚函数在多态中很重要。
多态指同样的消息被不同类型的对象接收时导致不同的行为。
虚函数机理:当编译器看到 fn 的虚函数标志时,会记下,等遇到这个虚函数的调用时,将
该捆绑操作滞后到运行中,以实际的对象来捆绑其对应的成员函数操作,编译器在捆绑操作
b.fn()处避开函数调用,只作一个指向实际对象成员函数的间接访问,每个实际的对象都需
额外占有一个指针空间,以指向类中的虚函数表。
11. 什么是运算符重载?它如何增强 C++的扩展性?
运算符重载是对已有的运算符赋予多重含义,使得同一个运算符作用于不同类型的数据
时导致不同的行为。
运算符重载的本质就是函数重载,可以改变现有运算符的操作方式,以使用于类类型,
为类的用户提供了一个直接的接口,使得用户程序所用的语言是面向问题的,而不是面向机
器的,增强了 C++的扩展性。
12. 请说明函数模板和模板函数的区别和联系。
函数模板是对一类同构函数的抽象定义,它并不是函数,函数模板的定义被编译时,不
会产生任何执行代码。
模板函数:通过用户提供的具体参数,C++编译器在编译时刻能够将函数模板实例化,
根据同一个模板创建出不同的具体函数,这些函数之间的不同之处主要在于函数内部一些数
据类型的不同,而由模板创建的函数的使用方法与一般函数的使用方法相同。
函数模板的重点是模板,它表示的是一个模板,用来生成函数。而模板函数的重点是函
数,它表示的是由一个模板生成而来的函数。
13.STL 是什么?组成部分和区别。
STL 是 c++提供的标准模板库。
STL 的主要组成部分为:容器、迭代器、算法、函数对象和适配器。其中算法处于核心
地位,迭代器如同算法和容器之间的桥梁,算法通过迭代器从容器中获取元素,然后将获取
的元素传递给特定的函数对象的操作,最后将处理后的结果存储到容器中。
二、编程题
1.编写一个程序,求最小公倍数和最大公约数。
#include
using std::cin ;
using std::cout ;
using std::endl ;
int gcd( int , int ) ; //函数 gcd 用于求两个正整数的最大公约数
int main( )
{
int num1 , num2 , leastCommonMultiple , greatestCommonDivisor ;
cout << "请输入两个非零正整数:" ;
cin >> num1 >> num2 ;
leastCommonMultiple = gcd( num1 , num2 ) ;
//两个数的最小公倍数等于这两个数的乘积除以这两个数的最大公约数
greatestCommonDivisor = num1 * num2 / leastCommonMultiple ;
cout << '\n' << num1 << " 和 " << num2 << " 的 最 大 公 约 数 为 : " <<
leastCommonMultiple << "\n\n"
<< num1 << " 和 " << num2 << " 的 最 小 公 倍 数 为 : " <<
greatestCommonDivisor << endl ;
return 0 ;
}
int gcd( int n1 , int n2 )
{
int temp , r ;
if( n1 < n2 )
//将大数放在 n1 之中,将小数放在 n2 之中
{
}
temp = n1 ;
n1 = n2 ;
n2 = temp ;
while( n2 != 0 )
//利用辗转相除法求最大公约数
{
r = n1 % n2 ;
n1 = n2 ;
n2 = r ;
}
return n1 ;
}
2.编写一个程序,计算输入的一系列整数之和。假定:输入的第一个整数为连续输入的整数
的个数。【要求每条输入语句仅读取一个整数】
#include "stdafx.h"
#include
using std::cin ;
using std::cout ;
using std::endl ;
int main( )
{
int num ,value , sum = 0 ;
cout << "Enter the number of values to be processed: " ;
cin >> num ;
for( int i = 0 ; i < num ; i ++ )
cout << "Enter a value: " ;
cin >> value ;
sum += value ;
{
}
cout << "Sum of the " << num << " values is " << sum << endl ;
return 0 ;
}
3.编写程序,计算 1~20000 之间的质数,输出时要求每行 10 个数。
#include
using std::cout ;
#include
using std::setw ;
bool prime( int ) ;
//判断是否是质数
int main( )
{
int count = 0 ;
cout << "The prime numbers from 1 to 20000 are:\n" ;
for ( int loop = 2; loop <= 20000 ; ++loop )
if ( prime( loop ) ) {
++count ;
cout << setw( 6 ) << loop ;
if ( count % 10 == 0 )
cout << '\n' ;
}
return 0;
}
//对于 2 以后的数字 n 先看 n 是否是 2 的倍数,然后再判断是否能被 3 , 5 , 7 ... sqrt(n)整除
以提高效率
bool prime( int num )
{
}
if( num == 2 )
return true ;
if( num == 1 || num % 2 == 0 )
return false ;
for( int loop2 = 3 ; loop2 <= sqrt( (double)num ) ; loop2 += 2 )
{
}
if ( num % loop2 == 0 )
return false ;
return true ;
4.编写一个程序,利用如下的公式计算 的值,精确到 。
#include
using std::endl ;
using std::cin ;
using std::cout ;
using std::ios_base ;