C++语言
1.1.全局变量和局部变量在内存中是否有区别?如果有,是什么区别?
解析:
1)预备知识——程序的内存分配
一个由C/C++编译的程序占用的内存分为以下几个部分:
(1)栈区(stack)——由编译器自动分配、自动释放,比如存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。
(2)堆区(heap)——一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于链表。
(3)全局静态区——全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域(.data),未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(.bss)。程序结束后由系统释放。
(4)文本常量区——常量字符串就是放在这里的(.rodata)。程序结束后由系统释放。
(5)程序代码区——存放函数的二进制代码(.text)。
2)static全局变量与普通全局变量有什么区别?Static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
解:
(1)全局变量的说明之前再加上static就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上没有什么区别。这两者的区别在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义了该变量的源文件内有效,在同一源程序的其他源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数使用,因此,可以避免在其他源文件中引起错误。
(2)从以上分析可以看出,把局部变量改变为静态局部变量后是改变了它的存储方式,即改变了它的生存期。把全局变量改变为静态全局变量后,是改变了它的作用域,限制了它的使用范围。
(3)Static函数与普通函数作用域不同,仅在本文件中。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件说明,要使用这些函数的源文件要包含这个头文件。
综上所述:
static全局变量与普通的全局变量有什么区别?
static全局变量只初始化一次,防止在其他文件单元中被引用。
static局部变量和普通局部变量有什么区别?
static局部变量只初始化一次,下一次依据上一次的结果值。
static函数与普通函数有什么区别?
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。
1.2.static有什么用途?(至少说明两种)
解:
(1)限制了变量的作用域;
(2)改变了变量的存储域;
1.3.从实现原理上来说重载(overload)和重写(override)的区别?
解:
(1)重载
A. 作用域(在同一个类中)
B. 函数名相同;
C. 函数参数不相同;
D. virtual关键字可有可无;
(2)重写
A. 作用域(基类和派生类中)
B. 函数名相同;
C. 函数参数相同;
D. 必须含有virtual关键字;
1.4.试述动态内存分配和静态内存分配的主要区别
解:
内存的静态分配和动态分配的区别主要是两个:
一是时间不同。静态分配发生在程序的编译和连接的时候。而动态分配则发生在程序调入和执行的时候。
二是空间不同。堆是动态分配的,没有静态分配的堆。栈是静态分配的,由编译器自动完成。
1.5.C++语言中的浮点数组的内存如何静态分配和释放,语法上有何要求?
解:
不会。
1.6.下面代码能否通过编译?如果可以,其输出结果是什么?同时解释原因.
1 #include <iostream> 2 #include <cassert> 3 using namespace std; 4 5 unsigned HextoDec(char *hex) 6 { 7 assert(hex != NULL); 8 unsigned num = 0; 9 //skip the space 10 while(*hex == ' ') 11 { 12 hex++; 13 } 14 15 //calculate 16 while(*hex) 17 { 18 if(*hex >= 'a' && *hex <= 'f') 19 { 20 num = num * 16 + *hex - 'a' + 10; 21 } 22 else if(*hex >= 'A' && *hex <= 'F') 23 { 24 num = num * 16 + *hex - 'A' + 10; 25 } 26 else if(*hex >= '0' && *hex <= '9') 27 { 28 num = num * 16 + *hex - '0'; 29 } 30 else 31 { 32 //此时出现问题,返回已经转换的值 33 return num; 34 } 35 hex++; 36 } 37 return num; 38 } 39 40 int main() 41 { 42 char *f = "ff"; 43 cout << HextoDec(f) << endl; 44 }
解:
可以编译通过,运行结果如下所示。
A::f() B::f() B::g(A *) B::g(A *)
1.7. 试写出派生类对象初始化时构造函数的调用顺序,以及派生类对象被删除时,析构函数的调用顺序。(即基类和派生类哪个先调用)
解:
以下面这个代码进行查看。
1 #include <iostream> 2 #include <cassert> 3 using namespace std; 4 5 unsigned HextoDec(char *hex) 6 { 7 assert(hex != NULL); 8 unsigned num = 0; 9 //skip the space 10 while(*hex == ' ') 11 { 12 hex++; 13 } 14 15 //calculate 16 while(*hex) 17 { 18 if(*hex >= 'a' && *hex <= 'f') 19 { 20 num = num * 16 + *hex - 'a' + 10; 21 } 22 else if(*hex >= 'A' && *hex <= 'F') 23 { 24 num = num * 16 + *hex - 'A' + 10; 25 } 26 else if(*hex >= '0' && *hex <= '9') 27 { 28 num = num * 16 + *hex - '0'; 29 } 30 else 31 { 32 //此时出现问题,返回已经转换的值 33 return num; 34 } 35 hex++; 36 } 37 return num; 38 } 39 40 int main() 41 { 42 char *f = "ff"; 43 cout << HextoDec(f) << endl; 44 }
运行结果如下所示。
从运行结果可以看出:
先执行基类的构造函数,然后若派生类中含有其他类类型成员,则调用其构造函数,最后调用派生类的构造函数。
而析构函数的调用顺序与构造函数的调用顺序正好相反。
1.8.试述struct和class的区别
解:
二者最本质的一个区间就是默认的访问控制、默认的继承访问权限。
struct是public,class是private的。
另外,class这个关键字还用于定义模板参数,就像typename关键字一样。而struct关键字则不可以。
1.9.什么是多态?多态有什么好处?
解:
(1)什么是多态?
一种接口多种实现。同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。也就是所谓的动态绑定,要触发动态绑定,必须满足两个条件:第一,只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不能进行动态绑定;第二,必须通过基类类型的引用或指针进行函数的调用。
(2)为什么要用多态?
我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块;它们的目的都是为了代码重用。而多态除了代码的复用外,还可以解决项目中紧耦合的问题,提供程序的可扩展性。耦合度讲的是模块与模块之间,代码与代码之间的关联度。通过对系统的分析,把它们分解成一个一个子模块,子模块提供稳定的接口,达到降低系统耦合度的目的。
(3)多态有什么好处?
A. 应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大的提供了程序的可复用性。//继承
B. 派生类的功能可以被基类的方法或引用变量所调用,这是向后兼容,可以提高可扩充性和可维护性。
1.10.什么是内联函数,在什么情况下应该考虑使用内联函数?它有什么代价?
解:
(1)在普通的函数定义前加上inline关键字即可,另外,类的成员函数在类内部定义,则默认为内联函数。
(2)代码量比较小,并且递归调用层次不深,或是经常被调用的函数。
(3)虽然可以减少函数调用的开销,但是会使代码膨胀。
1.11.用C++编程实现将表示十进制整数的字符串转换成表示十六进制整数的字符串:比如“168” —> "0xA8"。注意输入输出都是字符串。
解:
先把字符串转化为函数,即实现atoi()函数,然后进行处理即可。
1.12.用C++编程实现将一个以一个字符串形式表示的十六进制数转化为一个十进制整数。(不考虑溢出)
解:
1 #include <iostream> 2 #include <cassert> 3 using namespace std; 4 5 unsigned HextoDec(char *hex) 6 { 7 assert(hex != NULL); 8 unsigned num = 0; 9 //skip the space 10 while(*hex == ' ') 11 { 12 hex++; 13 } 14 15 //calculate 16 while(*hex) 17 { 18 if(*hex >= 'a' && *hex <= 'f') 19 { 20 num = num * 16 + *hex - 'a' + 10; 21 } 22 else if(*hex >= 'A' && *hex <= 'F') 23 { 24 num = num * 16 + *hex - 'A' + 10; 25 } 26 else if(*hex >= '0' && *hex <= '9') 27 { 28 num = num * 16 + *hex - '0'; 29 } 30 else 31 { 32 //此时出现问题,返回已经转换的值 33 return num; 34 } 35 hex++; 36 } 37 return num; 38 } 39 40 int main() 41 { 42 char *f = "ff"; 43 cout << HextoDec(f) << endl; 44 }
上面程序只考虑字符串前面的空格,若出现非十六进制字符串则返回当前已经转化好的数字。