C/C++面试

1. RTTL

运行时类别识别,在只有一个指向基类的指针或引用时确定一个对象的准确类型。

2.什么是拷贝构造函数

是单个形参的构造函数,实参是与该类同属一类的对象;在类定义中,如果未提供自己的拷贝构造函数,C++提供一个默认拷贝构造函数,该默认拷贝构造函数完成一个成员到另一个成员的拷贝。

3. 什么是深浅拷贝

深拷贝:不共享内存,拷贝内存的内容。两个内存中内容相同但是相互独立。

浅拷贝:只是复制指针,共享内存。

typedef struct info

{

   char name[10];

   int age;

}INFO,*PINFO;

typedef INFO *pinfo;

 

void main()

{

   INFO info1 = {"cat", 2};

   pinfo p1;

   PINFO p2;

   p1 = (pinfo)malloc(sizeof(INFO));

   p1->age = 4;

   sprintf(p1->name,"mycat");

   p2 = (pinfo)malloc(sizeof(INFO));

   p2->age = p1->age;

   sprintf(p2->name,p1->name);

 

   printf("%s %d ",p1->name,p1->age);

   printf("%s %d ",p2->name,p2->age);

   printf("%s %d ",info1.name,info1.age);

  

 

   system("pause");

}

浅拷贝:只是复制指针,共享内存。

typedef struct info

{

   char name[10];

   int age;

}INFO,*PINFO;

typedef INFO *pinfo;

 

void main()

{

   INFO info1 = {"cat", 2};

   pinfo p1;

   PINFO p2;

   p1 = (pinfo)malloc(sizeof(INFO));

   p1->age = 4;

   sprintf(p1->name,"mycat");

   p2 = p1;

   p2->age = 8;

 

   printf("%s %d ",p1->name,p1->age);

   printf("%s %d ",p2->name,p2->age);

   printf("%s %d ",info1.name,info1.age);

   system("pause");

}

4.面向对象设计的优点

开发时间短,效率高,可靠性强。面向对象编程的编码具有可重用性,可以在应用大量采用成熟的类库(如STL),从而缩短了开发时间,软件易于维护和升级。

5.const有什么用途?

在C/C++中:(1)可以定义const常量,(2)修饰函数的返回值和形参;

在C++中,还可以修饰函数的定义体,定义类的const成员函数。被const修饰的东西收到强制保护,可以防止意外变动,提高了程序的健壮性。

6.C++默认有哪些成员函数?

默认构造函数、析构函数、赋值构造函数、赋值函数

7.继承层次中,为什么基类析构函数是虚函数?构造函数不能使用虚函数?

编译器总根据类型来调用类成员函数。但是一个派生类的指针可以安全地转化为一个基类指针。这样删除一个基类的指针时,C++不管这个指针指向一个基类对象还是一个派生类对象,调用的都是基类的析构函数而不是派生类的。如果你依赖于派生类的析构函数代码来释放资源,而没有重载析构函数,那么会有资源泄露。

虚函数采用一种虚调用的方法。虚调用是一种可以在只有部分信息的情况下工作的机制。如果创建一个对象,则需要知道对象的准确类型。因此构造函数不能为虚函数。

如果虚函数是有效的,为什么不把所有的函数设置为虚函数?

不行,首先,虚函数是有代价的。由于每个虚函数的对象都要维护一个虚函数表,因此在使用虚函数的时候会产生一定的系统开销,这是没必要的。

8.什么是多态?

多态是将基函数的指针或者引用指向派生类的对象。多态通过虚函数机制实现。多态的作用是接口重用。

9.覆盖和重载的区别?

虚函数是基类希望派生类重新定义的函数,派生类重新定义基类虚函数的做法叫做覆盖。

重载时在允许在相同作用域中存在多个同名函数,只是函数的形参列表不同。

10.共有继承、受保护继承、私有继承?

公有继承,派生类对象可以访问的公有成员,派生类成员函数可以访问基类中公有和受保护的成员。

私有继承,基类的成员只能被直接派生类的成员访问,无法再往下继承;

受保护继承,基类的成员只被直接派生类对象访问,但不能再往下继承。

11.哪几种情况只能使用构造函数初始化列表而不能用赋值初始化?

const成员,引用成员

12.在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?
答:首先,extern是C/C++语言中表明函数和全局变量作用范围的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。
通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。extern "C"是连接申明(linkage declaration),被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:void foo( int x, int y );该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。
所以,可以用一句话概括extern “C”这个声明的真实目的:解决名字匹配问题,实现C++与C的混合编程。

13.头文件中的ifndef/define/endif有什么作用?

答:这是C++预编译头文件保护符,保证即使文件被多次包含,头文件也只定义一次。

14.const和#define有什么区别?

答:(1)const和#define都可以定义常量,但是const用途更广。

(2)const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
(3) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。

15.指针和引用的区别?

答:指针和引用都提供了间接操作对象的功能。

(1) 指针定义时可以不初始化,而引用在定义时就要初始化,和一个对象绑定,而且一经绑定,只要引用存在,就会一直保持和该对象的绑定;

(2) 赋值行为的差异:指针赋值是将指针重新指向另外一个对象,而引用赋值则是修改对象本身;

(3) 指针之间存在类型转换,而引用分const引用和非const应用,非const引用只能和同类型的对象绑定,const引用可以绑定到不同但相关类型的对象或者右值

16.哪一种成员变量可以在一个类的实例之间共享?

答:static静态成员变量

17.C++如何阻止一个类被实例化?一般在什么时候将构造函数声明为private?

答:(1)将类定义为抽象基类或者将构造函数声明为private;

(2)不允许类外部创建类对象,只能在类内部创建对象

18.main函数执行之前会执行什么?执行之后还能执行代码吗?

答:(1)全局对象的构造函数会在main函数之前执行;

(2)可以,可以用_onexit 注册一个函数,它会在main 之后执行;

如果你需要加入一段在main退出后执行的代码,可以使用atexit()函数,注册一个函数。

#include<stdlib.h>
#include <stdio.h>
int atexit(void(*function)(void));
void fn1(void), fn2(void), fn3(void);

int main(void)
{
atexit(fn2);
atexit(fn1);
printf("This is executed first. ");

system("pause");
}
void fn1()
{
printf("This is");

}
void fn2()
{
printf(" executed next. ");
system("pause");
}

19.进程间如何通信?

答:信号、信号量、消息队列、共享内存

20.在网络编程中涉及并发服务器,使用多进程与多线程的区别?

答:(1)线程执行开销小,但不利于资源管理和保护;进程则相反,进程可跨越机器迁移。

(2)多进程时每个进程都有自己的内存空间,而多线程间共享内存空间;

(3)线程产生的速度快,线程间通信快、切换快;

(4)线程的资源利用率比较好;

(5)线程使用公共变量或者资源时需要同步机制。

21.TCP和UDP有什么区别。

答:

TCP——传输控制协议,提供的是面向连接、可靠的字节流服务。

当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。

UDP——用户数据报协议,是一个简单的面向数据报的传输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快.

TCP协议和UDP协议的一些特性区别如下:

1.TCP协议在传送数据段的时候要给段标号;UDP 协议不需要。

2.TCP协议可靠;UDP协议不可靠。

3.TCP协议是面向连接;UDP协议采用无连接。

4.TCP协议负载较高,采用虚电路;UDP协议低负载。

5.TCP协议的发送方要确认接受方是否收到数据段(3次握手协议)。

6.TCP协议采用窗口技术和流控制。

22.类使用static成员的优点,如何访问?

答:优点:

(1)static 成员的名字是在类的作用域中,因此可以避免与其他类的成员或全局对象名字冲突;

(2)可以实施封装。static 成员可以是私有成员,而全局对象不可以;

(3) static 成员是与特定类关联的,可清晰地显示程序员的意图。

static 数据成员必须在类定义体的外部定义(正好一次),static 关键字只能用于类定义体内部的声明中,定义不能标示为static. 不像普通数据成员,static成员不是通过类构造函数进行初始化,也不能在类的声明中初始化,而是应该在定义时进行初始化.保证对象正好定义一次的最好办法,就是将static 数据成员的定义放在包含类非内联成员函数定义的文件中。

静态数据成员初始化的格式为:

<数据类型><类名>::<静态数据成员名>=<值>

类的静态数据成员有两种访问形式:

<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>

23. static数据成员和static成员函数

答:(1)static数据成员:
static数据成员独立于该类的任意对象而存在;每个static数据成员是与类关联的对象,并不与该类的对象相关联。Static数据成员(const static数据成员除外)必须在类定义体的外部定义。不像普通数据成员,static成员不是通过类的构造函数进行初始化,而是应该在定义时进行初始化。
(2)static成员函数:
Static成员函数没有this形参,它可以直接访问所属类的static成员,不能直接使用非static成员。因为static成员不是任何对象的组成部分,所以static成员不能被声明为const。同时,static成员函数也不能被声明为虚函数。

24. 完成字符串拷贝可以使用 sprintf、strcpy 及 memcpy 函数,请问这些函数有什么区别

,你喜欢使用哪个,为什么?

答案:这些函数的区别在于 实现功能以及操作对象不同。

(1)strcpy 函数操作的对象是字符串,完成从源字符串到目的字符串的拷贝功能。

(2)sprintf 函数操作的对象不限于字符串:虽然目的对象是字符串,但是源对象可以是字符串、也可以是任意基本类型的数据。这个函数主要用来实现(字符串或基本数据类型)向字符串的转换功能。如果源对象是字符串,并且指定 %s 格式符,也可实现字符串拷贝功能。

(3)memcpy 函数顾名思义就是内存拷贝,实现将一个内存块的内容复制到另一个内存块这一功能。内存块由其首地址以及长度确定。程序中出现的实体对象,不论是什么类型,其最终表现就是在内存中占据一席之地(一个内存区间或块)。因此,memcpy 的操作对象不局限于某一类数据类型,或者说可适用于任意数据类型,只要能给出对象的起始地址和内存长度信息、并且对象具有可操作性即可。鉴于memcpy 函数等长拷贝的特点以及数据类型代表的物理意义,memcpy 函数通常限于同种类型数据或对象之间的拷贝,其中当然也包括字符串拷贝以及基本数据类型的拷贝。

对于字符串拷贝来说,用上述三个函数都可以实现,但是其实现的效率和使用的方便程度不同:

• strcpy 无疑是最合适的选择:效率高且调用方便。

• sprintf 要额外指定格式符并且进行格式转化,麻烦且效率不高。

• memcpy 虽然高效,但是需要额外提供拷贝的内存长度这一参数,易错且使用不便;并且如果长度指定过大的话(最优长度是源字符串长度 + 1),还会带来性能的下降。其实 strcpy 函数一般是在内部调用 memcpy 函数或者用汇编直接实现的,以达到高效的目的。因此,使用 memcpy 和 strcpy 拷贝字符串在性能上应该没有什么大的差别。

对于非字符串类型的数据的复制来说,strcpy 和 snprintf 一般就无能为力了,可是对 memcpy 却没有什么影响。但是,对于基本数据类型来说,尽管可以用 memcpy 进行拷贝,由于有赋值运算符可以方便且高效地进行同种或兼容类型的数据之间的拷贝,所以这种情况下 memcpy 几乎不被使用 。memcpy 的长处是用来实现(通常是内部实现居多)对结构或者数组的拷贝,其目的是或者高效,或者使用方便,甚或两者兼有。

25. C++函数中值的传递方式有哪几种?

答:三种传递方式为:值传递、指针传递和引用传递

26. C++里面是不是所有的动作都是main()引起的?如果不是,请举例.

比如全局变量的初始化,就不是由main函数引起的

举例: class A{};

A a; //a的构造函数限执行

int main() {}

27. static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?

答:static全局变量与普通全局变量区别:static全局变量只初使化一次,防止在其他文件单元中被引用;

static局部变量和普通局部变量区别:static局部变量只被初始化一次,下一次依据上一次结果值;

static函数与普通函数区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。

29. 有1,2,....一直到n的无序数组,求排序算法,并且要求时间复杂度为O(n),空间复杂度O(1),使用交换,而且一次只能交换两个数。

#include<iostream>
using namespace std;

int main(){
int a[] = { 10, 6, 9, 5, 2, 8, 4, 7, 1, 3 };
int len = sizeof(a) / sizeof(int);
int temp;
for (int i = 0; i < len;)
{
temp = a[a[i] - 1];
a[a[i] - 1] = a[i];
a[i] = temp;
if (a[i] == i + 1)
i++;
}
for (int j = 0; j < len; j++)
cout << a[j] << ",";

system("pause");
return 0;
}

原文地址:https://www.cnblogs.com/my-cat/p/6169119.html