【C++基本概念面试题】

【面试题1】 什么是C语言语句,预处理指令是不是语句 

答案:语句就是以分号作为分隔符,编译后产生机器指令的代码。预处理指令不是语句,因为预处理指令都不是以分隔符结尾。

【面试题2】 变量的声明和定义有什么区别

答案 :为变量分配地址和存储空间的称为定义,不分配内存的称为声明。一个变量可以在多个地方声明,但只在一个地方定义。加入extern修饰的是变量的声明,说明此变量将在文件外或在文件后面部分定义。

【面试题3】 下列字符中哪些不是C语言关键字

A:int 、char、extern

B:  printf、include、define

C:  sizeof、go、cout

D:  while、for、sizeof

答案:B, printf是标准库函数不是关键字,include和define是预处理指令,也不是C语言的关键字。注意D中sizeof,它的使用类似于函数,sizeof(int)

【面试题4】 下列变量定义中,哪些是合法的

A:  short  _b  a =1-.le-1;                //变量名不能有空格

B:  double b = 1 + 5e2.5;               

C:  long do=0xfdaL;                      //do是关键字

D:  float 2_and=1-e-3                    //变量名不能以数字开头

知识点:C语言用户自定义变量规则、保留字不能做自定义变量

在使用一个字符串作为C语言中的变量名时,这个字符串必须满足下面的要求:

(1) 只能包含数字、ASCII字母和下画线。变量名不能包含除"_"以外的任何特殊字符,如:%,#,,等,变量名不能包含空白字符(换行符、空格和制表符)。

(2)变量必须以字母或下划线开头,而不能以数字开头。

(3)不能用保留字作为变量名。

【面试题5】 如何以最简单的方式让电脑蜂鸣器发出声音

#include <stdio.h>

int main( int argc, char *argv[] )

{

printf(" \7");

return 0;

}

【面试题6】 谈谈你对编程规范的理解或认识

编程规范可总结为:程序的可行性、可读性、可移植性及可测试性。

【面试题7】 函数、变量等命名名称规则

含数字、ASCII字母、下划线,以字母或者下画线开头,不能用保留字作变量名的情况下,还要有很高的可读性。

可读性应该是本题最好的答案:

1、标识符最好采用英文单词或其组合,便于记忆和阅读

2、标识符应简单明了,不要过长

3、命名使用驼峰法或小写加下划线

4、指针变量命名:p+变量类型前缀+命名,pp+变量类型前缀+命名...

5、程序中不要出现标识符完全相同的局部变量和全局变量,不会发生语法错误,但不利于程序的可读性

6、用正确的反义词组命名具有互斥意义的变量或相反动作的函数等

7、常量全用大写的字母,用下划线分割单词

       #define  WM_USR_NET(4009)

       const int MAX_LENGTH=100

8、全局变量前加前缀g_(表示global)

9、类的数据成员加前缀m_(表示member),这样可以避免数据成员与成员函数的参数同名。

【面试题17】 什么是左值,什么是右值?

答案:左值主要代表地址,右值主要用做数值。右值:存储在某内存地址中的数值,也称为变量的数据。左值:存储数据值的那块内存的地址。也称为变量的地址值。

【面试题19】 sizeof和strlen的区别

答案:sizeof和strlen有以下区别:1)sizeof是一个操作符,strlen是库函数。2)sizeof的参数可以是数据的类型,也可以是变量,而strlen只能以结尾为'\0'的字符串为参数3)编译器在编译时就计算出了sizeof的结果,而strlen函数必须在运行时才能计算出来,并且sizeof计算的是数据类型占内存的大小,而strlen计算的是字符串的实际长度 4)数组做sizeof的参数不退化,传递给strlen就退化为指针(因为数组作为参数传递给函数时,传递的是指向数组首地址的指针而不是数组数据结构)

结构体

【面试题20】 结构体是()数据类型

C、C++数据类型分为:基本数据类型、构造数据类型(数组、结构、联合)、指针类型、空类型

答案:结构体是构造数据类型

【面试题21】 结构体可以直接赋值吗?

答案:声明时可以直接初始化,同一结构体的不同对象之间也可以直接赋值,但是当结构体中含有指针“成员”时一定要小心。

注意:当有多个指针指向同一段内存时,某个指针释放这段内存可能会导致其他指针的非法操作。因此在释放前一定要确保其他指针不再使用这段内存空间,可类比类的复制构造函数。

【面试题23】 计算学生不及格的人数并打印他们的性别、姓名和成绩

#include "stdio.h"

struct student

{

        char *name;

        int score;

        char sex;

};

int main()

{

         int i=0, totle = 0;

         student stu[7] = {

          {"Li1", 85, 'M'},

          {"Li2", 25, 'M'},

           {"Li3", 64, 'F'},

           {"Li4", 47, 'F'},

            {"Li5", 90, 'M'},

             {"Li6", 12, 'M'},

             {"Li7", 100, 'M'},

         };

        for( i=0; i<7;i++)

        {

                  if(stu[i].score < 60)

                   {

                    }

         }

}

【面试题24】 结构体内存对齐问题

struct s1
{
       int    i:8;
       char j:4;
       int   a:4;
       double b;
};

struct s2
{
       int    i:8;
       char j:4;
       double b;
       int   a:4;
};

struct s3
{
       int    i;               //4
       char j;               //1
       double b;          //8  b是最大的数据类型,因此i,j,a都要向b对齐为8个字节,四个数据共占据32个字节
       int   a;               //4
};
printf("sizeof(s1)=%d\n", sizeof(s1));               16字节
printf("sizeof(s2)=%d\n", sizeof(s2));                24字节
printf("sizeof(s3)=%d\n", sizeof(s3));                

知识点:位域和结构体数据长度对齐

C和C++区别

【面试题25】 关键字static在C和C++中区别

【面试题26】 C语言的结构体和C++的有什么区别

预处理、保留字

预处理是指在进行编译的第一遍扫描(语法扫描和语法分析)之前所做的工作。预处理是C、C++语言的一个重要的功能特征,它由预处理程序负责完成。C、C++提供多种预处理功能,如宏定义、文件包含、条件编译等。合理地使用预处理功能,可使程序便于阅读、修改、移植和调试,也有利于模块化程序设计。

【面试题1】简述#ifdef、#else、#endif和#ifndef的作用

答案:这些条件编译指令主要有以下功能:1)利用#ifdef、#endif可将某程序功能模块包括进去,以向特定用户提供该功能 2)用于在子程序前加上标记,以便于追踪和调试   3)应对硬件的限制

【面试题2】 宏定义和函数

答案:1)宏的引用只占编译时间,不占运行时间 2)宏的引用没有返回值 ,如果需要,需给整个表达式加上括号  3)宏的形参无类型。函数形参必须要有类型   4)实参为表达式的情况,如果没有给表达式加上括号,可能会导致错误的结果,而函数不会 5)宏直接替代可能导致副作用,函数不会

注意:使用宏时一定要注意宏的直接替换带来的隐患,这种隐患不可能完全避免,但是可以尽量减少

【面试题3】 用#define声明一个常数

用宏定义实现一个常数,用来表明一年有多少秒,忽略闰年的问题。要注意数据长度的问题。(16位机)

#define  SECONDS_PER_YEAR  (365*24*60*60)UL

【面试题4】写一个标准的宏MIN

#define min(a,b) ((a)<=(b)?(a):(b))

注意:在调用时一定要注意这个宏定义的副作用,如下调用((++*p)<(x)?(++*p):(x)) p指针就自加了两次,违背了MIN的本意

 【面试题5】typedef和define有什么区别

答案:1)用法不同:typedef用来定义一种数据类型的别名,增强程序的可读性。define主要用来定义常量,以及书写复杂、使用频繁的宏 2)执行时间不同:typedef是编译过程的一部分,有类型检查的功能 define是宏定义,是预编译的部分,其发生在编译之前指示简单地进行字符串的替换,不进行类型的检查 3)作用域不同:typedef有作用于限定,define不受作用于约束,只要是在define声明后的引用都是正确的 4)对指针的操作不同:typedef和define定义的指针有很大的区别

注意:typedef定义是语句,因为句尾要加分号,而define不是语句,千万不能再句尾加分号

【面试题5】#define CHAR char*  和 typedef  char* CHAR 各有什么优劣

答案:由define定义的类型别名可以被其他修饰符扩展(如:unsigned)而typedef不可以。define定义的类型别名代表指针时,其连续声明的变量只有第一个是指针,其他的均为非指针的普通变量。而typedef能够保证连续声明的所有变量都是同一类型。

【面试题6】谈谈你对typedef的认识

答案:typedef共有四种用途:1)定义一种类型的别名 2)用在旧的C代码中辅助声明struct  3)定义与平台无关的类型  4)为复杂的声明定义一个新的简单的别名

还有两个注意事项:

1)定义了一种类型的新别名后不能被其他的修饰符扩展

2)typedef是并不真正影响对象的存储特性的存储类关键字

typdef  PCHAR  char *

PCHAR  a, b;   

定义了一个字符指针变量a和一个字符变量b。这是typedef相对于define的有事

const(常量)

【面试题8】关键字const是什么

【面试题9】说明以下a声明的含义

static(静态)和extern

【面试题11】static有什么作用

面试题12】extern有什么作用

答:extern标识的变量或函数声明定义在别的文件中,提示编译器遇到此变量或函数时在其他模块中寻找其定义。

【面试题13】简述变量存储类型

答:变量的存储类型定义如下:【存储类型】【类型】【变量名表】变量的存储类型分为四种:自动类型【auto】、寄存器类型【register】、静态类型【static】、外部类型【extern】。变量的存储类型是对变量作用域、存储空间、生存期的规定。

【面试题14】volatile有什么作用

volatile定义变量的值是易变的。有如下作用:

1)状态寄存器一类的秉性设备硬件寄存器

2)一个中断服务子程序会访问到的非自动变量

3)多线程间被几个任务共享的变量

在嵌入式编程中状态寄存器变量会随时被外界条件改变属于这类型的变量。在多线程编程中临界变量被几个线程共享,也是“易变的”,也应为这种类型的变量。

【面试题15】一个参数可以既是const又是volatile吗

const修饰的变量在程序中是只读的,不能被改变的。但这仅限于程序内部,它可以被程序外部改变。例如const修饰的端口,程序内部不能修改它的值,但是外部却可以。但是编译器会优化掉const修饰的变量。

用volatile和const来同事修饰一个变量,比如外部端口。const volatile char* port = (volatile const char*)0x025e;

答:可以,用const和volatile同时修饰变量,表示这个变量在程序内部是只读的,不能改变的,只在程序外部条件下改变,并且编译器不会优化这个变量。每次使用这个变量时,都要小心地去读取这个变量的值,而不是去寄存器读取它的备份。

说明:在此一定要注意const的意思,const只是不允许程序中的代码改变某一变量,其在编译期发挥作用,它并没有实际地禁止某段内存的读写特性。

【面试题16】一个指针可以是volatile吗

可以,因为指针

引用和指针

指针时C语言的重要特征。利用指针技术,可以描述各种复杂的数据结构,高效地支持动态内存分配。在C++中又引入了引用的新特性,它允许程序来负责确定把参数传递给函数的方法。指针和引用是C、C++程序设计的精华,相似又相互区别。

引用

【面试题1】什么是引用

答案:用用就是一个目标变量的别名,对引用的一切操作和对变量的直接操作是一样的。主要用做函数的参数、函数返回值和常引用。

说明:引用可以理解为常量指针,也就是指针值一经确定就不能再改的特殊指针,并且这种特殊指针没有自己的内存空间。但有些时候指针并不能实现引用的功能,比如运算符重载时返回值应为引用,而不应用指针。

【面试题2】常引用有什么作用

答案:常引用的引入主要是为了避免使用变量的引用时,在不知情的情况下改变变量的值。常引用主要用于定义一个普通变量的只读属性的别名、作为函数的传入形参,避免实参在调用函数中被意外地改变。

说明:很多情况下,需要用常引用作为形参,被引用对象等效于常对象,不能在函数中改变实参的值,这样的好处是有较高的易读性和较低的出错率。

【面试题3】流操作符重载为什么返回引用

在程序中,流操作符>>和<<经常连续使用。因此这两个操作符的返回值应该是一个仍旧支持这两个操作符的流引用。其他的数据类型都无法做到这一点。

注意:在除赋值操作符和流操作符之外的其他一些操作符中,如+、-、*、/等却千万不能返回引用值。因为这四个操作符的对象都是右值,因此,它们必须构造一个对象作为返回值。

 

指针

【面试题4】说明以下声明的含义

A:int(**p)[10] ;

B:  char*(*p)[10];

C:  float (*p[10])();

D:  double*((*p)[10]);

E:  short (*p) (char);

F:  long(*(*p)(int,int))(int);

知识点:数组指针、指针数组、函数指针

int *p[10];         定义了数组p,数组元素是int型的指针 

int (*p)[10];      定义了数组指针p,p指向一个10个元素数组,数组的元素是int型数组

int* p(int)         定义了函数p,这个函数p有一个int型参数,返回值为int型指针

int (*p) (int)     定义了一个函数指针p,p所指向的函数有一个int型参数,返回值为int型数据

答案:A:  p为数组指针的指针,数组有10个元素,元素为int型数据

           B:   p为数组的指针,数组有10个元素,元素为char*型数据

           C:  p为数组,数组有10个元素,元素为函数指针类型,这个函数没有参数,返回值为float型数据

           D: p为数组的指针,数组有10个元素,元素为double*型数据

           E: p为函数指针,它所指向的函数有一个char型的参数,返回值为short型数据

           F: p为函数指针,它所指向的函数有两个int型的参数,返回值为函数指针型数据,这个返回的函数指针指向的函数有一个int型的参数,返回值为Long型数据

【面试题5】简述指针常量与常量指针的区别

指针常量:定义了一个指针,这个指针的值只能在定义时初始化,其他地方不能改变。

char * const p1;

int  * const p2;

常量指针:定义了一个指针,这个指针指向一个只读的对象,

int const *p1;

const int *p1;

指针常量强调的是指针的不可改变性,而常量指针强调的是指针对其所指对象的不不可改变性。

注意:

无论是指针常量还是常量指针,其最大的用途就是作为函数的形式参数,保证实参在被调用函数中的不可改变特性。

【面试题6】写出以下代码的输出

【面试题7】找出代码的错误

 

指针和数组

数组名和指针有太多的相似。

【面试题8】写出代码的输出结果

 

【面试题9】请问这段代码有什么问题

【面试题10】a和&a有什么区别

 

【面试题11】请问这段代码有什么问题

【面试题12】数组名和指针的区别

函数指针

“野指针”

动态内存

 

字符串

【面试题1】编码实现数字转换为字符串

编码实现itoa(), 设计一个程序把一个数字转换为字符串存储到一个缓冲区。例如把数字 5486321 转换为 “5486321”

int myItoa(int num, char *p, int n)
{

    if(p == NULL)  //校验指针有效性
    {
        return -1;
    }
    
    if(num < 0)    //判断数值是否为负值
    {
        *p++ = '-';
        num = 0 - num;  //将负值转换为正值
    }
    int temp= 0;
    *p = 0;
    if(n==16)      //按16进制转换
    {

    }
    else if(n==10) //按10进制转换
    {
        for(int i=0; i<10;i++)
        {
            temp = int(num/pow(10,9-i));
            if(temp !=0 ) //确定数值转换成字符的开始位置
            {
                *p = 1;
            }
            if(*p != 0)
            {
                *p++ = temp + '0';
                num = num % int(pow(10,9-i));
            }
        }

    }

*p += '\0';

return 0;
}

【面试题2】编码字符串转换为数字

编码实现atoi(),设计一个程序,把一个字符串转换为整型数值。例如数字 “5486321”转换成字符:5486321

 

【面试题3】编写一个标准strcpy函数

字符串以‘0’结尾,是解决这个问题的关键

void strcpy(char *str1, char *str2)
{
    while((*str1++=str2++) != '\0');  //拷贝知道str2结束
}

初级版

以上代码知识简单实现了功能,需要完善的地方还有很多

(1)str2传入的指针所指向的内容应该是只读型的,不应该在函数内被改变

(2)指针str1和str2在没有检验的情况下就直接使用,这是不规范的

(3)为了实现链式操作,还应把目的地址返回

char * strcpy(char *str1, const char *str2)
{
    assert((str1 !=NULL)&&(str2 != NULL)) //判断指针的合法性
    char *address = str1 ;                //记录目标指针所指向的地址
    while((*str1++=str2++) != '\0');      //拷贝知道str2结束
    return address;
    //返回目标地址
}

注意:编程是一定要注意编程细节,注意对形参指针合法性的检验,以及程序可扩展性的设计。

【面试题4】简述strcpy、sprintf与memcpy的区别

答案:三者主要有以下不同之处:

1)操作对象不同,strcpy的两个操作对象均为字符串,sprintf的操作源对象可以是多种数据类型,目的操作对象是字符串,memcpy的对象就是两个任意可操作的内存地址,并不限于何种数据类型。

2)执行效率不同,memcpy最高,strcpy次之,sprintf的效率最低

3)实现功能不同,strcpy主要实现字符串变量间拷贝,sprintf主要实现其他数据类型格式到字符串的转化,memcpy主要是内存块间的拷贝

字符串与数组

很多情况下对字符串的操作都是通过数组形式进行的。

【面试题5】找出程序的错误之处

复习三个知识点:

1)字符串以'\0'结尾

2)数组的下标从0开始

3)要掌握函数strcpy和strlen的工作方式

strcpy函数通过源字符串的结束符'\0'来判断何时结束拷贝,拷贝的长度包含'\0'

strlen获得字符串的长度是不包含'\0'的。

注意:

字符串是以'\0'结尾的,而strcpy和strlen也是依据字符串的这一特性工作的,所以在平时使用时一定要注意,特别是把一个字符串赋值给一个数组变量是,要注意字符串的长度是strlen计算的结果+1,要注意数组下标越界的问题。

【面试题6】判断程序会出现什么问题

使用数组和字符串时,一定要注意字符串和数组常见的三个问题:

1)数组不要越界

2)字符串以'\0'结尾

3)strcpy拷贝时'\0'为结束拷贝标志

 

嵌入式编程

【面试题1】编码实现某一变量某位清0或置1

#define BIT3 (0x01<<3)

static int a ;

void set_bit3(void)

{

        a |= BIT3;   //将a第3位置1

}

void clr_bit3(void)

{

       a &= ~BIT3; //将a第3位清0

}

 

【面试题2】用C写一个死循环程序

   while(1){}

 

【面试题3】用变量a给出下面的定义

A:一个整型数    int a = 0;

B: 一个指向整型数据的指针   int *a = NULL;

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);

 

【面试题4】设置地址为0x67a9的整型变量的值为0xaa66

int *ptr;

ptr = (int *)0x67a9;

*ptr = 0xaa66;

 

【面试题5】评论下面这个中断函数

__interrupt double compute_area(double radius)
{
    double area = PI * radius * radius;
    printf("Area=%f", area);
    return area;
}

中断服务子程序有以下几个特点:
1)不能返回值
2)不能传递参数
3)使用时要避免重入和性能问题

ISR中不要做浮点运算,有些处理器需要额外的寄存器入栈。
printf()经常有重入和性能上的问题

 

【面试题6】评价一个代码片段

unsigned int zero = 0;

unsigned int compzero = 0xFFFF;

不能说以上代码错误,但是这两句只能运行在16位的处理器上。

 

unsigned int zero = 0;

unsigned int compzero =~0;

注意:嵌入式编程一定要注意程序的可移植性。

 

 

面向对象

【面试题1】谈谈你对面向对象的认识

面向对象可以理解成对待每一个问题,都是首先要确定这个问题由几部分组成,而每一个部分其实就是一个对象。然后再分别设计这些对象,最后得到整个程序。传统的程序设计多是基于功能的思想来进行考虑和设计的,而面向对象的程序设计则是基于对象的角度来考虑问题。这样做能够使得程序更加简洁、清晰。

【面试题2】面向对象的三大特征

面向对象的三大特征是封装性、继承性、多态性。

封装性:将客观事物抽象成类,每个类对自身的数据和方法实行protection

继承性:广义的继承有三种实现形式:实现继承、可视继承、接口继承

多态性:是将父类对象设置成为和一个或多个它的子类对象相等的技术。把子类对象给父类对象赋值之后,父类对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。

【面试题3】面向对象和面向过程有什么区别

面向过程就是指分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。

面向过程是把构成问题的事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题步骤中的行为。

说明:

面向对象面向的是数据结构,面向过程面向的是算法。虽然面向对象在数据结构方面优于面向过程,但是面向过程是算法设计的实现基础,面向对象的程序设计最终还要转化为面向过程。

类的成员变量和成员函数

【面试题4】简述类Public、protect、private的作用

public的变量和函数在类的内部、外部都可以访问,private修饰的变量和函数只有在类的内部可以访问; protect修饰的变量和函数在类的内部可以访问,还可以在派生类中访问。

说明:

public、private、protected是实现面向对象的封装特性的关键。控制了类的接口访问权限,并控制了子类对父类的继承关系。

【面试题5】大端、小端

大端模式:是指数据的低位(就是数据权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中。小端模式:是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。

 

【面试题6】C++的空类有哪些成员函数

   缺省构造函数

   缺省拷贝构造函数

   缺省析构函数

    缺省赋值运算符

    缺省取址运算符

    缺省取址运算符const

需要注意:只有当实际使用这些函数的时候,编译器才会去定义它们。

 

构造函数和析构函数

构造函数没有返回值,可以带参数,用于创建对象时初始化数据成员。

析构函数没有返回类型、没有参数,不能随意调用,只有在类对象生命周期结束的时候,由系统自动调用。

【面试题7】构造函数能否为虚函数,析构函数呢?

答案:构造函数不能是虚函数,而且不能再构造函数总调用虚函数,因为那样实际执行的是父类的对应函数,因为自己还没有构造好。析构函数可以是虚函数,而且,在一个复杂类结构中,这往往是必需的。析构函数也可以是纯虚函数,但纯虚析构函数必需有定义体,因为析构函数的调用实在子类中隐含的。

说明:

虚函数的动态绑定特性是实现重载的关键技术,动态绑定根据实际的调用情况查询相应类的虚函数表,调用相应的虚函数。

 

【面试题8】简述子类与父类的析构、构造函数的调用顺序

构造函数调用的次序是先基类后派生类,即定义一个对象时先调用基类的构造函数、然后调用派生类的构造函数。而析构过程恰好相反,先析构子类对象,再调用父类的析构函数。

 

【面试题9】编写类String的构造函数、析构函数和赋值函数

class String
{
    public:
    String(const char *str = NULL);  //普通构造函数
    String(cosnt String &other);     //拷贝构造函数
    ~String(void);                   //析构函数
    String &operator = (const String &other); //赋值函数
    
    char *m_data; //用于保存字符串
};

//普通构造函数
String::String(const char* str)
{
    int length=strlen(str);
    m_data = new char[length+1];
    strcpy(m_data,str);
}

//析构函数
String::~String(void)
{
    delete[] m_data;
}

//拷贝构造函数
String::String(const String &other)
{
    int length = strlen(other.m_data);
    m_data = new char[length+1];
    //若能加上NULL判断更好
    strcpy(m_data,other.m_data);
}

//赋值函数
String& String::operator=(const String &other)
{
    if(this == &other)
        return *this;
    if(m_data != NULL)
    {
        delete[] m_data;
    }

    int length = strlen(other.str);
    m_data = new char[legth+1];

    //此处加上NULL判断会更好
    strcpy(m_data,other.m_data);

    return *this;
    
}

注意:在实现编程时,申请内存空间前要把指向要申请的这段内存空间的指针置空,以便检验是否申请成功。申请后,最好检验是否申请成功,如果申请失败,要提示错误,这样能够防止内存访问错误,避免“野指针”。

 

【面试题11】谈谈对拷贝构造函数和赋值构造函数的认识

拷贝构造函数和赋值运算符重载有以下两个不同之处:

1)拷贝构造函数生成新的类对象,而赋值运算符不能。

2)由于拷贝构造函数是直接构造一个新的类对象,所以在初始化这个对象之前不用检验源对象是否和新建对象形同。而赋值运算符则需要这个操作,另外赋值运算中如果原来的对象由内存分配,要先把内存释放掉。

注意: 当有类中有指针类型的成员变量时,一定要重写拷贝构造函数和赋值运算符,不要使用默认的、

 

继承和多态

 

【面试题1】指出程序的错误

继承关系和和子类对父类成员的访问特性表

成员属性\继承方式publicprivateprotected
publicpublicprivateprotected
privateprivateprivateprivate
protectedprotectedprivateprotected

 

继承关系和子类对父类成员的访问特性

 

成员属性\继承方式publicprivateprotected
public可见不可见不可见
private不可见不可见不可见
protected不可见不可见不可见

 

子类继承父类时如果不显式指定继承类型,则默认的继承类型为私有继承(private)。而私有继承时,子类不能访问父类的成员。

【面试题2】用C++设计一个不能被继承的类

要实现继承,类的构造函数和析构函数是关键。因为子类的构造函数会自动调用父类的构造函数。子类的析构函数也会自动调用父类的析构函数。所以要想使一个类不能被继承,只要把它的构造函数和析构函数都定义为私有函数或保护函数,当一个类视图从这个类继承是,必然会编译出错。构造函数和析构函数都是私有,那么怎么来得到该类的实例呢?可以通过定义静态函数来创建和释放类的实例,实现该类不能继承但能被实例化的功能。

【面试题3】虚函数和纯虚函数1

虚函数充分体现了面向对象思想中的继承和多态性这两大特性。纯虚函数就是实现接口技术的关键。

【面试题4】虚函数和纯虚函数2

 

多态

【面试题5】简述类成员函数的重写、重载和隐藏的区别

1)重写和重载主要有以下几点不同。

     范围的区别:被重写函数和重写函数在两个类中,而重载和被重载函数在同一个类中。

     参数的区别:被重写函数和重写函数的参数列表一定相同,而重载和被重载函数的参数列表一定不同。

     virtual的区别:重写的基类中被重写的函数必须要有virtual修饰,而重载函数和被重载函数可以被virual,也可以没有

2)隐藏和重写、重载有以下几点不同

      与重载的范围不同,和重写一样,隐藏函数和被隐藏函数不在同一个类中。

      参数的区别:隐藏函数和被隐藏函数的参数列表可以相同,也可以不同,但是函数名肯定是要相同的。当参数不相同时,无论基类中的参数是否被virtual修饰,基类的函数都是被隐藏,而不是被重写。

说明:

重载和覆盖都是实现多态的基础,但是两者实现的技术完全不相同,达到的目的也完全不同,覆盖是动态绑定的多态,而重载是静态绑定的多态。

【面试题6】简述多态实现的原理

有虚函数的类都有一个虚函数表,虚函数表是实现多态的关键

每一个含有虚函数的类,其实例对象内部都有一个虚函数表指针,该虚函数表指针被初始化为本类的虚函数表。

答案:编译器发现一个类中有虚函数,便会立即为此类生成虚函数表vtable。虚函数表的各表项为指向对应虚函数的指针。编译器还会在此类中隐含插入一个指针vptr指向虚函数表。调用此类的构造函数时,在类的构造函数中,编译器会隐含执行vptr与vtable的关联代码,将vptr指向对应的vtable,将类与此类的vtable联系了起来。另外在调用类的构造函数时,指向基础类的指针此时已经变成指向具体的类的this指针,这样依靠此this指针即可得到正确的vtable。如此才能真正与函数体进行连接,这就是动态联编,实现多态的基本原理。

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++初级工程师面试通常会考察基础理论知识、语言运用能力以及对常见问的解决方法。以下是一些常见的面试: 1. **基础概念**: - C++的核心特性有哪些(如封装、继承和多态)? - 指针和引用的区别是什么? 2. **语法与数据类型**: - 什么是静态变量和局部变量?它们的生命周期是怎样的? - 常量与常量指针有何不同? 3. **内存管理**: - C++中的内存分配方式有哪些?比如栈内存和堆内存? - 什么是构造函数和析构函数? 4. **控制结构**: - 何为条件语句(if-else, switch)、循环语句(for, while)及其使用场景? - 异常处理机制(try-catch)的基本用法是什么? 5. **STL(标准模板库)**: - 描述一下vector、list、set和map的主要区别。 - 队列和栈在哪些情况下使用? 6. **面向对象编程**: - 如何实现单例模式?为什么它不推荐在现代C++中使用? - C++中的纯虚函数和抽象类有什么作用? 7. **模板和泛型编程**: - C++中的模板是什么?模板元编程是什么? - 举例说明如何使用模板进行类型安全的操作? 8. **错误处理和调试**: - 遇到运行时错误(如 segmentation fault)时,你会如何定位问? - 如何使用gdb或其他调试工具? **相关问**: 1. 你能解释一下C++中的运算符重载吗? 2. 当你在代码中遇到性能瓶颈,你会如何优化? 3. 什么是RAII(Resource Acquisition Is Initialization)?它在C++中的作用是什么? 如果你有具体的面试目或者需要深入了解某一方面,随时告诉我,我会帮助你解析和提供答案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值