程序员面试题宝典

程序员面试题宝典
程序员面试题宝典

1、用预处理指令#define声明一个常数,用以表明一年中有多少秒?

答:#define SECOND_PER_YEAR (60*60*24*365)UL

2、写一个“标准”宏MIN这个宏输入两个参数并返回较小的一个。

答:#define MIN(A,B) ((A)<=(B)?(A):(B))

3、c onst 有什么用途?(至少说明两种)

答:(1) 、可以定义const 常量。

(2)、const可以修饰函数的参数和返回值,甚至函数的定义体。被const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

4、c onst 和#define相比有什么不同?

答:C+语言可以用con st定义常量,也可以用#defi ne定义常量,但是前者比后者有更多的优点:

(1)、const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料到的错误(边际效应) 。

⑵、有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。在C++S序中只使用con st常量而不使用宏常量,即const常量完

全取代宏常量。

5、一个空类占多少空间?多重继承的空类呢?答:一个空类所占空间为1 ,多重继承的空类所占空间还是1 。

6、内联函数和宏的差别是什么?答:内联函数和普通函数相比可以加快程序运行的速度,因为不需要中断调用,在编译的时候内敛函数可以直接被镶嵌到目标代码中;而宏只是一个简单的字符替换。

内联函数需要做参数类型检查,这是内联函数跟宏相比的优势。

inline 是指嵌入代码,就是在调用函数的地方不是跳转,而是把代码直接写到那里去。对于短小的代码来说,inline 可以带来一定的效率提升,而且和C时代的宏函数相比,inline更加安全可靠。可是这个是以增力口空间消耗为代价的。至于是否需要inline函数,这就需要根据实际情况取舍了。

inline 一般只用于如下情况:

(1)、一个函数不断被重复调用。

(2)、函数只有简单的几行,且函数内不包含for 、while、switch 语句。一般来说,我们写小程序没有必要定义成inline ,但是如果要完成一个工程项目,当一个简单函数被调用多次时,则应考虑用inline。

宏在C语言里极其重要,而在C+里用得就少多了。关于宏的第一规贝S是:绝不应该去使用它,除非你不得不这样做。几乎每个宏都表明了程序设计语言里或者程序里或者程序员的一个缺陷,因为它将在编译器看到程序的正文之前重新摆布这些正文。

宏是在代码处不佳任何验证的简单替代,而内联函数是讲代码直接插入调用处,而减少了普通函数调用时的资源消耗。

宏不是函数,只是在编译前(编译预处理阶段)将程序中有关字符串替换成宏体。

inline 函数是函数,但在编译中不单独产生代码,而是将有关代码嵌入到调用处。

指针与引用

7、指针和引用的差别?

答:(1) 、非空区别。在任何情况下都不能使用指向空值的引用。一个引用必

须总是指向某些对象。因此如果你使用一个变量并让它指向一个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。相反,如果变量肯定指向一个对象,例如你的设计不允许变量为空,这时你就可以把变量声明为引用。不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针要高。

(2)、合法性区别。在使用引用之前不需要测试它的合法性。相反,指针则应该总是被测试,防止其为空。

(3)、可修改区别。指针与引用的另一个重要的不同是指针可以被重新赋值以指向另一个不同的对象。但是引用则总是指向在初始化时被指定的对象,以后不能改变,但是指定的对象其内容可以改变。

(4)、应用区别。总的来说,在一下情况下你应该使用指针:一是你考虑到存在不指向任何对象的可能;二是你需要能够在不同的时刻指向不同的对象。如果总是指向一个对象并且一旦指向一个对象后就不会改变指向,那么你应该使用引用。

8写出函数指针、函数返回指针、con st指针、指向con st的指针、指向const

的const扌旨针

答:void (*f)()

void* f()

const int *

int* const

const int* const

9、下面的数据声明都代表什么?

(1)、float(**def)[10];//def 是一个二级指针、它指向的是一个一维数组的指针,数组元素都是float 类型。

(2)、double*(*gh)[10];//gh 是一个指针,它指向一个一维数组

⑶、double(*f[10])();//f 是一个数组,f有10个元素,元素者E是函数的

指针,指向的函数类型是没有参数且返回double的函数。

⑷、int*((*b)[1O]);〃跟int*(*b)[10]是一样的,b是一维数组的指针。

(5)、Long(*fun)(int)// 函数指针

(6)、int (*(*F)(int,int))(int)//F 是一个函数的指针,指向的函数的类型是有两个int 参数并且返回一个函数指针的函数,返回的函数指针指向有一个int 参数且返回int 的函数。

10、用变量a给出下面的定义:

a)、一个整型数int a;

b)、一个指向整型数的指针int *a;

c)、一个指向指针的指针,它指向的指针是指向一个整型数int **a;

d)、一个有10个整型数的数组int a[10];

e)、一个有10个指针的数组,该指针是指向一个整型数int *a[10];

f)、一个指向有10个整型数数组的指针int (*a)[10]

g)、一个指向函数的指针,该函数有一个整型数参数并返回一个整型数int (*a)(int);

h)、一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数int (*a[10])(int)

11、C+中有了malloc/free,为什么还需要new/delete?

答:malloc与free是C++/C语言中的标准库函数,new/delete是C++勺运算符。它们都可用于申请动态内存和释放内存。

对于非内部数据类型的对象而言,光用malloc/free 无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free 。因此C+语言需要一个能完成动态内存分配和初始化工作的运算符new以及一个能完成清理与释放内存工作的运算符delete。new/delete不是库函数,而是运算符。

12、指针与句柄的区别和联系是什么?

答:句柄和指针其实是两个截然不同的概念。Window系统用句柄标记系统资源,用句柄隐藏系统的信息。你只要知道有这个东西,然后去调用就行了,它是个32bit的uint。指针则标记某个物理内存地址,是不同的概念。

面向对象

13、面向对象技术的基本概念是什么? 答:对象、类和继承。

14、C+中的空类默认产生哪些类成员函数?答:对于一个空类,编译器默认产

生4 个成员函数:默认构造函数、析构函数、拷贝构造函数和赋值函数。

15、结构体是否可以拥有构造函数和析构函数及成员函数?如果可以,那么结构体和class 还有区别么?

答:区别是class中变量默认是private , struct中的变量默认是

public。struct可以有构造函数,析构函数,之间也可以继承等等。C+中的struct 其实和class意义一样,唯一不同的就是struct里面默认的访问控制

权限是public , class中默认的访问控制权限是private。C+中存在

struct关键字的唯一意义就是为了让C程序员有个归属感,是为了让C+编译

器兼容以前用C开发的项目。

16、哪一种成员变量可以在同一个类的实例之间共享?答:必须使用静态成员变量在一个类的所有实例间共享数据。如果想限制对静态成员变量的访问,则必须把它们声明为保护类型或者是私有类型。不允许用静态成员变量去存放某一个对象的数据。静态成员数据是在这个类的所有对象间共享的。

17、以下这个类声明正确吗?为什么?

class A

{

const int Size = 0;

}; 答:该类声明存在着成员变量初始化问题。常量必须在构造函数的初始化列

表里面初始化或者将其设置成static。正确的声明方式如下:

class A

{

A()

{const int Size = 9;}

};

或者

class A

{

static const int Size = 9;

};

18、析构函数可以是内联函数么?答:析构函数可以是内联函数。

19、MF(类库中,CObject类的重要性不言自明。在CObject的定义中,我们看到一个有趣的现象,即CObject的析构函数是虚拟的。为什么MFC的编写者认为virtual destructors are necessary ?

答:将CObject的析构函数设为virtual型,贝则所有CObject类的派生类

的析构函数都将自动变为virtual 型,这保证了在任何情况下,不会出现由于析构函数未被调用而导致的内存泄漏。这才是MFC将CObject::~CObject() 设为virtual型的真正原因。

20、析构函数可以为virtual 型,构造函数贝不能。那么为什么构造函数不能为虚呢?

答:虚函数采用一种虚调用的办法。虚调用是一种可以在只有部分信息的情况下工作的机制,特别允许我们调用一个只知道接口而不知道其准确对象类型的函数。但是如果要创建一个对象,你势必要知道对象的准确类型,因此构造函数不能为虚。

21、如果虚函数是非常有效的,我们是够可以把每个函数都声明为虚函数?答:不行,这是因为虚函数是有代价的:由于每个虚函数的对象都必须维护一个V 表,因此在使用虚函数的时候都会产生一个系统开销。如果仅是一个很小的类,

且不想派生其他类,那么根本没必要使用虚函数。

22、编写类String 的构造函数、析构函数和赋值函数。

class String

{

public:

String(const char *str = NULL);// 普通构造

String(const String &other);// 拷贝构造

~String(void); // 析构函数

String &oprate =(const String &other);// 赋值private:

char *m_data;

};

四个函数的编写如下:

(1) 、String 的析构函数

String::~String(void)

{

delete []m_data;

或者delete m_data;

}

(2) 、String 的构造函数

String::String(const char *str)

{

if(str == NULL)

{

m_data = new char[1];

*m_data = '\0';

}

else

{

int length = strlen(str);

m_data = new char[length+1];

strcpy(m_data,str);

}

}

(3) 、String 的拷贝构造函数

String::String(const String &other)

{

int length = strlen(other.m_data);

m_data = new char[length+1];

strcpy(m_data,other.m_data);

}

(4) 、String 的赋值函数

String &String::operate =(const String &other)

{

if(this == &other)

return this;

// 释放原有的内存资源

delete []m_data;

// 分配新的内存资源,并复制内容

int length = strlen(other.m_data);

m_data = new char[length+1];

strcpy(m_data,other.m_data);

// 返回本对象的引用

return *this;

}

23、什么是多态?多态的作用是什么?

答:开门、开窗户、开电视机等。这里的“开”就是多态!多态可以简单的概括为一个接口、多种方法,在程序运行的过程中才决定调用的函数。多态性简单的说就是一句话:允许将子类类型的指针赋值给父类类型的指针。多态的作用是:实现接口重用。

24、什么是虚函数?答:虚函数就是允许被其子类重新定义的成员函数。

25、重载和覆盖有什么不同呢?

答:虚函数总是在派生类中被改写,这种改写被称为“override(覆盖)”。

覆盖是指派生类重写基类的虚函数,就像我们前面在B类中重写了A类中的虚函数foo()。重写的函数必须有一致的参数表和返回值

overload 约定成俗的被翻译为“重载”,是指编写一个与已有函数同名但是参数列表不同的函数。例如一个函数既可以接受整型数作为参数,也可以接受浮点数作为参数。重载不是一种面向对象的编程,而只是一种语法规则,重载与多态没有什么直接关系。

继承和接口

相关主题
相关文档
最新文档