C++复试常见题集结

1.delete,malloc,new,free四者之间的关系
我们在进行C++程序编写的时候,不可避免的会使用面向对象的方式,但是对于我们自己编写的类来说,我们通常称之为非内部的数据结构类型,此时对于free/malloc这种标准的C/C++库函数来说,是不可能完成执行构造函数和析构函数的作用的,而C++的标准运算符new和delete可以完成此项工作,new用于进行动态的内存分配和初始化工作,delete可以完成对象的清理和释放工作。
2.delete和delete[ ]的区别
我们在进行面向对象的程序设计时,会自建数据类型,但是对于我们通过new出来的自建数据类型的释放有需要注意的地方。简而言之就是用new分配的,需要通过delete来进行相应的释放,而通过new[ ]分配的内存,需要通过delete [ ]来进行释放,但是对于内部已有的数据类型来说不存在此种限制。
3.C++面向对象三大特性:封装 继承 多态
4.子类的析构和基类的析构的调用情况
一句话,基类和子类之间的构造或者析构函数可以通过洋葱圈模型类予以解释,调用构造函数时,会先调用基类的构造函数,然后深入子类,而析构正好与之相反,先调用子类的,再调用父类的。
5.多态 虚函数 纯虚函数
首先多态产生的条件便是继承,方法重写,父类引用指向子类对象。会通过父类来根据相同的指令调用子类不同的方法,而虚函数和纯虚函数之间是有区别的,虚函数需要定义加上代码的实现,而纯虚函数不需要,并且如果一个类中如果存在纯虚函数,那么此类不能进行实例化,只能继承,虚函数便没有此种限制。
6.引用 以及需要注意的问题
引用便是我们在操作某一个变量时所起的别名,引用在创建时本身就不是一个数据类型,并不占有存储单元,因此系统也不会为之分配内存,引用声明以后,就相当于存在两个名字指向一块地址,但是不能再为引用创建引用。
7.将引用作为函数参数的特点是什么
将目标变量的引用作为函数的参数和将指针作为函数的参数的效果相同,但是不同的是我们需要对指针作为的形参分配存储空间,而对引用作为的形参不需要分类存储空间。
8.什么时候使用常引用
如果我们需要提高程序的效率,又希望我们的程序变量在函数内部不进行改变,那我们可以通过常引用的方式来进行编写程序。
9.全局变量和局部变量相关
C++的内存区域可以分为堆区和栈区,以及静态存储区,局部变量存储在栈区,函数结束后自动进行释放,全局变量存储在静态存储区,程序退出后才进行释放,另外堆区存放的是由new,malloc开辟,需要通过程序员本身调用delete,free进行释放。
10.基类的析构函数不是虚函数,会带来什么问题
在面向对象程序设计中,我们经常会见到虚函数,但是并不是每一个类的析构函数都是虚函数,如果某一个类为基类并且产生继承和多态时,一般将析构函数设置为虚函数,如果不这样做的话,那么在父类指针指向子类对象的时候,父类指针此时的析构函数并不是虚函数,在delete此指针的时候,只会调用父类的,而不会调用子类的,会导致内存泄漏。
11.介绍内存的分配方式
程序运行起来会产生3个区,主要的变量都会几种在这三区内。
首先是静态存储区,程序运行开始便出现,其内的主要成员保罗全局变量等等,在程序运行结束后进行释放。
其次是栈区,主要存储函数的局部变量,在函数内部有效,函数执行结束后会被自动释放掉。
最后是栈区,主要通过new或者malloc方式来开辟内存,有程序员手动释放。
12.const VS #define
const常量与宏常量define之间使用方式类似,但是const应用时会进行安全类型检查,在程序的编译,运行时起作用,而define则在程序的预处理阶段,只进行简单的字符串转换。并且某些编译器可以对const进行调试,而不能对宏常量进行调试,使用const可以避免不必要的内存分配,节省空间。
13.代码识别

void * ( * (*fp1)(int))[10];   //1

解释:首先fp1是一个指针,指向一个函数,这个函数的参数为int类型,函数的返回值也是一个指针,这个指针是一个数组,这个数组有10个元素,每一个元素是一个void*指针。

float (*(* fp2)(int,int,int))(int); //2

解释:fp2是一个指针,指向一个函数,这个函数有三个int类型的参数,函数返回值也为指针,指向一个函数,这个函数的参数为int类型,返回值为float类型。

int (* ( * fp3)())[10]();    //3

解释:fp3是一个指针,指向一个函数,这个函数的参数为空,函数的返回值也为一个指针,这个指针指向一个数组,这个数组有10个元素,每一个元素是一个指针,指向一个函数,函数的参数为空,返回值为int类型。

int id[sizeof(unsigned long)];  //4

解释:上面的代码正确,sizeof为编译时的元素符,编译时便确定了,可以看成与机器有关的常量。

 int (*s[10])(int);  //5

解释:为一个函数指针数组,首先第一个int为返回值,而*s[10]为指针数组,s是含有10个指针的数组,第二个int是参数列表,(*p)(int)是一个函数指针,所以总计为一个函数指针数组。

    char str1[] = "abc";
  char str2[] = "abc";

  const char str3[] = "abc";
  const char str4[] = "abc";

  const char *str5 = "abc";
  const char *str6 = "abc";

  char *str7 = "abc";
  char *str8 = "abc";

  cout << ( str1 == str2 ) << endl;//0  分别指向各自的栈内存
  cout << ( str3 == str4 ) << endl;//0  分别指向各自的栈内存
  cout << ( str5 == str6 ) << endl;//1指向文字常量区地址相同

  cout << ( str7 == str8 ) << endl;//1指向文字常量区地址相同

解释:str1到str4都是数组常量,他们都有自己的内存地址或者内存空间,但是str5到str8为指针,他们都指向相同的区域。

int  a=4;

int  &f(int  x)

{    a=a+x;

      return  a;

}

int main(void)

{    int   t=5;

     cout<<f(t)<<endl;    //a = 9

    f(t)=20;              //a = 20

    cout<<f(t)<<endl;     //t = 5,a = 20  a = 25

     t=f(t);               // a = 30 t = 30

    cout<<f(t)<<endl;  }   // t = 60

}

14.引用和指针的区别
引用必须进行初始化,但是指针不需要,而且引用一旦初始化,便不可以更改其指向,更不可一指向空,但是指针不仅可以为一个空指针,而且可以更改指针的指向。
15.结构和联合
结构和联合都是由多个不同的数据类型成员组成,但在同一时刻,联合中值存放了一个被选中的成员,而结构的所有成员都存在。
对于联合的不同成员赋值,将会对其他成员进行重写,原来成员的值就不存在了,对于结构的不同成员赋值是不影响的。
16.重载和重写
重载是指重新编写同名函数,但是必须满足函数的参数不同,参数个数或者类型不同的前提条件,并且,重载和多态无关,但是重写不同,多态发生时便发生了重写。
另外关于地址绑定,重载是早绑定,在编译期间便绑定完毕,是静态的,但是重写是运行时绑定,属于晚绑定。
17.全局对象的构造函数会在main函数之前执行,并且C++不是类型安全的,两个不同类型的指针可以进行转换,在这方面C#是安全的.关于initialization list,如果一个类所有成员都是public且没有默认的构造函数,就可以用initialization list对类的成员进行初始化;assignment为赋值
18.UDP和TCP
UDP为用户报文协议,TCP为传输控制协议,TCP与UDP相比较而言更加安全可靠,但是UDP更加快读,使用UDP还是TCP要取决于程序要求。
19.消息映射
程序员指定MFC类(有消息处理能力的类)处理某个消息,完成对处理函数的编写, 来完成消息处理的功能。
20.windows消息系统由哪几部组成
windows的消息系统由三部分组成,分别是消息队列, 消息循环以及消息处理。
操作系统负责为进程准备一个消息队列,程序不断从消息队列中收取消息,接收消息。而应用程序也可以通过消息循环不断获取消息,处理消息。
消息处理便是消息循环将消息放到关联的窗口上进行处理。
21.将类的声明和实现分开的好处
可以起到保护的作用,其实可以提高编译的效率。
22.局部变量和全局变量
局部变量和全局变量的名字可以相同,但是局部变量会屏蔽全局变量,如果需要在同名的情况下使用全局变量,需要使用域运算符(::)。
23.assert()函数的使用
assert函数是一个调用程序时经常使用的宏,在程序运行时用来计算括号内的表达式,其宏定义存放在<assert.h>中,其函数原型为void assert(int expression);类似于python中的assert,如果我们在打开文件时进行assert,会起到很好的作用。在程序运行时会计算括号内的表达式,如果出错,则会终止程序的进行。
24.关于枚举类型
首先何为枚举类型,所谓的枚举类型便是C++的一种派生类型,是用户定义的若干枚举常量的集合,其声明形式为enum 枚举名 {变量列表}。例如如果我们有一个需求那就是系统记录一周的变量的那便是enum Weekday{SUN,MON.TUE,WED,THU,FRI,SAT};
值得注意的是:当我们需要一个变量,这个变量有好几种可能的取值的时候,我们可以将他定义为枚举类型。枚举类型有利于提高程序的可读性,从某种意义上来将,我们可以将其称之为一种“语法糖”。
25.class和struct
如果没有继承或者多态,那么class和struct两者的存储效率差不多相同,但是在C++中,class和struct是有着区别的,class成员默认为私有的,而struct默认为公有的。class和可以定义模板参数,但是struct不支持。
26.static函数和普通函数的区别
static静态函数默认的代码只限于本文件所有,而普通函数可以被其他代码文件所调用。
总结来说就是,其他文件可以拥有同名静态函数,静态函数不可被其他文件所有。
27.指针的几种情况
int p[n]:指针数组,一共n个元素,每个元素均为指向整型数据的指针.
int (
)p[n]:p为一个指针,指向一维数组,这个数组有n个整形数据。
int p():函数指针,p指向函数的返回值
int (
)p():p为指向函数的指针。
28.Debug和Release版本的区别
Debug是调试版本,Release是最终发送给用户的非调试的版本。
29.函数指针和指针函数
函数指针指的是指向一个函数入口的指针,而指针函数指的是函数的返回值是一个指针类型。
30.指针常量和常量指针
指针常量(int * const p),本质上是一个常量,指针用来说明常量的类型,在指针常量中,指针指向的值可以更改,但是指向的地址不可以更改。
常量指针(const int * p),本质上是一个指针,指针指向一个常量,指针指向的内容不可以更改,但是指向可以更改。
31.对指针的理解
指针是一个变量,指向一块内存地址,指针的类型取决于指针指向的类型,其也可以访问其指向的内存地址。
32.面向对象相关话语
面向对象的程序设计思想便是将数据结构和对数据结构的操作的方法封装成一个个的对象,而类便是将一些具有共性的对象封装起来,对象所具有的特征包括静态特征和动态特征。静态特征指的是描述对象的一些属性,动态特征指的是对象表现出来的行为。
类的定义与实现写在不同的文件上会提高编译的效率,因为分开的话只需要编译一次对应的obj文件,再次应用该类的地方就不会被编译,大大提高了效率。
–》成员函数通过this指针指向对象的首地址来区分不同对象的成员数据。
–》C++自动为类生成了四个缺省函数为:默认构造函数 拷贝构造函数 析构函数 赋值函数
33.关于内置函数
C++中类的成员函数定义可以分为几种实现方式,但是如果我们在类的内部实现了成员函数,我们默认实现的为较小规模的,但是系统在调用函数过程所花费的时间开销是巨大的。因此如果系统为了减少时间的开销,如果类内实现的成员函数不包括循环等控制结构,系统会默认将其编译为内置函数。默认inline定义,如果类内实现,那么便可以省略inline.
34.拷贝构造函数调用时机
①当一个对象去初始化另一个类的对象的时候
②如果函数的形参是类的对象,调用函数进行实参和形参结合的时候。
③如果函数的返回值是类对象,函数调用完成返回时。
关于构造函数,构造函数是类的一种特殊的成员函数,一般情况下,用来初始化对象成员变量,构造函数名字必须与类名相同,不具有任何类型,不具有返回值。
35.重写拷贝构造函数
通常情况下的一个原则是,如果我们在一个类中进行了new操作,我们便需要一个析构函数,同时我们也便需要一个拷贝构造函数。重写拷贝构造函数的原则便是包含动态分配成员或者包含指针成员的类都应该提供拷贝构造函数,同时提供拷贝构造函数的同时还应该考虑到重载“=”运算符。
另外,构造函数的调用顺序为先调用基类的构造函数,然后顺序初始化成员,然后调用自己的拷贝构造函数。
36.初始化成员列表的使用
首先,类对象的构造顺序为,分配内存,调用构造函数,显示或者隐式的初始化数据成员。
在以下三种情况下我们需要使用初始化列表:
①如果我们有一个类成员,本身就是一个类或者是一个结构,而且这个成员只有一个带参数的构造函数,而没有默认构造函数,如果要对此类进行初始化,就必须调用这个类成员的带参数的构造函数,如果没有初始化列表,第一步将无法完成。
②当类成员中含有一个const对象的时候,或者是一个引用的时候,也必须通过初始化成员列表进行初始化,因为这两种对象在声明后需要马上进行初始化操作,而在构造函数中赋值会报错。
③子类初始化父类的成员,仅仅只能在初始化列表中进行初始化。
37.静态成员函数
当我们在一个类中定义了静态私有成员的时候,只能通过静态成员函数来进行访问。当类的构造函数是私有的时候,不能像普通的类那样实例化自己,只能通过静态成员函数来调用构造函数来初始化自己。另外,如果我们想要在类外访问类的私有成员,我们可以通过下面的三种方式来进行访问,分别是,友元,继承以及共有的成员函数。
抽象类指的便是只能用来继承,而不能进行私有化的类。
运算符重载的意义在于为了使得用户自定义的数据类型的操作和内定义的数据类型的操作想同,运算符重载的三种方式分为普通函数,友元函数以及类成员函数。* 、sizeof、.、s三目元算符以及域运算符都不可以进行重载。
赋值运算符和拷贝构造函数之间的区别为都是将一个对象拷贝到另一个中去,不同的是拷贝构造函数需要建立一个新对象。
构造函数可以被重载,析构函数有且只有一个,且没有参数,不可以被重载。
全局对象的构造函数会在main之前执行。
38.类A
对一个类A不声明任何的成员函数和成员变量,但是Sizeof(A)仍不为0,举个反例,如果我们定一个class A[10]对象数组,如果为0,那么就无法区分A[0] A[1]…
堆栈溢出的原因一般是没有回收垃圾资源。构造函数不能声明为虚函数。
IP地址由两部分组成,分别为网络号和主机号。
switch()内的不能为浮点型,必须为整型或者枚举型。
一个函数频繁调用,C中为宏定义,C++为内联函数。
C++不是安全的,因此两个不同类型的指针可以进行强制转换。
C++值的传递方式:值传递 指针传递 引用传递
引用的时候加上尖括号表示从标准库路径开始查找,不加则从用户的工作目录开始查找。
39.static操作符
①static+局部变量 将一个变量声明为函数的局部变量,函数结束后变量不会被释放掉。
②static+全局变量 表示一个变量在当前文件的全局内科访问
③static+函数 表示一个函数在当前文件的全局内可访问
④static+类成员变量 表示这个成员为类所共有
⑤static+类成员函数 表示这个函数为全类所共有,而且只能访问静态成员变量
其作用是static+局部变量表示变量的作用范围为该函数体,该变量的内存只被分配一次,在下次调用时还维护上次的值。
static+全局变量或者函数指的是对整个模块可访问,其他模块不可访问。
static+类相关,表示在类共有,且static+类函数只能访问静态成员,不接受this指针。
40.const操作符
const修饰常量,定义时就被初始化,以后不能更改。const修改形参,那么该形参在函数体内不能进行任何的改变。
const修饰类成员函数,表示该函数只能对成员变量进行只读操作。
const用来阻止一个变量被改变。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章