1、1、什么是“引用”?申明和使用“引用”要注意哪些问题?引用就是某个目标变量的“别名”(alias),对引用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量的一个别名,它本身不是一种数据类型,此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。2、将“引用”作为函数参数有哪些特点?(1) 传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的
2、一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。(2) 使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。此外,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。(3) 使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用“*指针变量名”的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的
3、调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。3、在什么时候需要使用“常引用”?如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用“常引用” 。 “常引用”声明方式:const 类型标识符 const int ra=1; /错误a=1; /正确例 2string foo( );void bar(string 那么下面的表达式将是非法的:bar(foo( );bar(“hello world“);原因在于 foo( )和“hello world“串都会产生一个临时对象,而在 C+中,这些临时对象都是 const 类型的。因此,上面的表达式就是试图将
4、一个 const 类型的对象转换为非 const 类型,这是非法的。引用参数在能被定义为 const 的情况下,尽量定义为 const。4、将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?格式:类型标识符 int vals10;int error = -1;void main()put(0) = 10; / 以 put(0)函数值作为左值,等价于 vals0=10;put(9) = 20; / 以 put(9)函数值作为左值,等价于 vals9=20;cout = 0 . 而组合表示 contains-a 的关系,关联性强于聚合:组合类与被组合类有相同的生命周期,组合类要对被组合类负
5、责,采用实心的菱形表示组合关系:实现的形式是:class A.class B A a; . 9、面向对象的三个基本特征,并简单叙述之?(1) 封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected, public)。(2) 继承:广义的继承有三种实现形式:实现继承(使用基类的属性和方法而无需额外编码的能力) 、可视继承(子窗体使用父窗体的外观和实现代码) 、接口继承(仅使用属性和方法的名称、实现滞后到子类实现) 。(3) 多态:是将父对象设置成为和一个或更多的它的子对象相等的技术,用子类对象给父类对象赋值之后,父类对象就可以根据当前赋值
6、给它的子对象的特性以不同的方式运作。10、重载(overload )和重写(overwrite ,有的书也叫做“覆盖”)的区别?(常考的题目)从定义上来说:重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同) 。重写:是指子类重新定义父类虚函数。从实现原理上来说:重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的) 。如,有两个同名函数:spiff(int)和 spiff(double,double)。那么编译器做过修饰后的函数名称可能是这样的:_spiff_i、_spi
7、ff_d_d。对于这两个函数的调用,在编译期间就已经确定了,是静态的。也就是说,它们的地址在编译期间就已绑定(早绑定) ,因此,重载和多态无关!重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出) 。因此,这样的函数地址是在运行期绑定的(晚绑定) 。11、如何判断一个单链表是有环的?(注意不能用标志位,最多只能用两个额外指针)struct node char val; node *next;bool check(const node *head) /retu
8、rn false : 无环;true: 有环一种 O(n)的办法就是(搞两个指针,一个每次递增一步,一个每次递增两步,如果有环的话两者必然重合,反之亦然):bool check(const node *head)if (head = NULL)return false;node *low = head;node *fast = head-next;while (fast != NULL fast = fast-next-next;if (low = fast)return true;return false;12、多态的作用?主要是两个:(1) 扩展代码模块,实现代码重用;(2) 接口重用:为
9、了类在派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。13、ADO 与 ADO.NET 的相同与不同?除了能够让应用程序处理存储于 DBMS 中的数据这一基本相似点外,两者没有太多共同之处。但是 ADO 使用 OLE DB 接口并基于微软的 COM 技术,而ADO.NET 拥有自己的 ADO.NET 接口并且基于微软的.NET 体系架构。众所周知,.NET 体系不同于 COM 体系,ADO.NET 接口也就完全不同于 ADO 和OLE DB 接口,这也就是说 ADO.NET 和 ADO 是两种数据访问方式。ADO.NET 提供对 XML 的支持。14、C+ 是不是类型安全的?不是
10、。两个不同类型的指针之间可以强制转换(用 reinterpret_cast) 。C#是类型安全的。15、描述内存分配方式以及它们的区别?(1) 从静态存储区域分配。内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。速度快、不容易出错,因为有系统会善后。例如全局变量,static 变量等。(2) 在栈上分配。在执行函数时,函数内局部变量的存储单元都可在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。(3) 从堆上分配,即动态内存分配。程序在运行的时候用 malloc 或 new 申请任意大小的内存,程序员自己
11、负责在何时用 free 或 delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活。如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,另外频繁地分配和释放不同大小的堆空间将会产生堆内碎块。16、当一个类 A 中没有声明任何成员变量与成员函数,这时sizeof(A)的值是多少,如果不是零,请解释一下编译器为什么没有让它为零。(Autodesk)肯定不是零。举个反例,如果是零的话,声明一个 A a10对象数组,而每一个对象占用的空间是零,这时就没办法区分 a0,a1,。17、在 8086 汇编下,逻辑地址和物理地址是怎样转换的?(Intel)通用寄存器给出的地址是段内
12、偏移地址,相应段寄存器地址*10H+通用寄存器内地址,就得到了真正要访问的地址。18、分别写出 BOOL,int,float,指针类型的变量 a 与零的比较语句。BOOL : if (!a) or if(a)int : if ( a = 0)float : const EXPRESSION EXP = 0.000001if (a -EXP)pointer : if (a != NULL) or if(a = NULL)19、请说出 const 与#define 相比,有何优点?(1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没
13、有类型安全检查,并且在字符替换可能会产生意料不到的错误。(2) 有些集成化的调试工具可以对 const 常量进行调试,但是不能对宏常量进行调试。20、简述数组与指针的区别?数组要么在静态存储区被创建(如全局数组) ,要么在栈上被创建。指针可以随时指向任意类型的内存块。(1) 修改内容上的差别char a = “hello“;a0 = X;char *p = “world“; / 注意 p 指向常量字符串p0 = X; / 编译器不能发现该错误,运行时错误(2) 用运算符 sizeof 可以计算出数组的容量(字节数) 。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是 p 所指
14、的内存容量。C+/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意,当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。char a = “hello world“;char *p = a;cout #include #include using namespace std;void Order(vector int main(void)vector data;ifstream in(“c:data.txt“);if (in = NULL)cout temp;data.push_back(temp);in.close(); / 关闭输入文件流Order(data)
15、;ofstream out(“c:result.txt“);if (!out)cout int tag = false ; / 设置是否需要继续冒泡的标志位 for (int i = 1; i dataj+1)tag = true ;int temp = dataj;dataj = dataj+1;dataj+1 = temp;if (!tag)break;27、链表题:一个链表的结点结构struct Nodeint data;Node *next;typedef struct Node Node;(1) 已知链表的头指针 head,写一个函数把这个链表逆序 (Intel)Node* ReverseList(Node *head) / 链表逆序Node *p = NULL;Node *q = NULL;if (head = NULL )return head;p = head;head = NULL;while (p != NULL)q = p;p = p-next;q-next = head;