C++ 常见面试题目

const作用

(1)可以定义const常量,具有不可变性。 

(2)便于进行类型检查。(而宏不会进行类型检查)。

(3)可以保护被修饰的东西,防止意外的修改。

(4) 可以节省空间。

static作用

1.隐藏:一个文件中的全局变量在另外一个文件中使用extern声明就能使用,声明了static就不能了
  一个函数内的static变量具有全局生命期,但只在这个函数中可见

2.记忆功能和全局生存期

3.默认初始化为0

4.类的静态成员函数是属于整个类而非类的对象,所以它没有this指针

5.不能将静态成员函数定义为虚函数。

6.不可以同时用const和static修饰成员函数。

什么函数不能声明为虚函数
1:只有类的成员函数才能说明为虚函数;
2:静态成员函数不能是虚函数;
3:内联函数不能为虚函数;
4:构造函数不能是虚函数;
5:析构函数可以是虚函数,而且通常声明为虚函数。

指针和引用的区别

本质上:指针是一个新的变量,只是这个变量存储的是另一个变量的地址,我们通过访问这个地址来修改变量。

而引用只是一个别名,还是变量本身。对引用进行的任何操作就是对变量本身进行操作,因此以达到修改变量的目的。

1.引用必须被初始化,指针不必
2.引用初始化以后不能被改变,指针可以改变所指的对象。
3.不存在指向空值的引用,但是存在指向空值的指针。

4."sizeof引用"得到的是所指向的变量(对象)的大小,而"sizeof指针"得到的是指针本身的大小

封装、继承、多态

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

继承:代码复用,可以使得代码模块化,扩展已存在的代码

多态:一个接口,多种方法,程序在运行时才决定调用的函数, 作用:接口重用

          实现:子类重写父类虚函数,如果一个类中包含虚函数(virtual修饰的函数),那么这个类就会包含一张虚函数表,虚函数表存储的每一项是一个虚函数的地址

                     这个类的每一个对象都会包含一个虚指针,指向虚函数表,通过某个类型的指针访问某个成员时,编译器只是根据类型的定义查找这个成员所在偏移量,用这个偏移量获取成员

纯虚函数(抽象类

方法:virtual ReturnType Function()= 0;

该基类只做能被继承,而不能被实例化

这个方法必须在派生类中被实现

结构体、联合

#include "stdafx.h"
#include <iostream>
using namespace std;

union u {//联合,共同占用一段内存。
    char c;
    int i;
};

#pragma pack(2)//指定对齐字节数
struct MyStruct //每个成员都有自己独立的地址
{
    short s;
    int i; //最大为4字节
    char c;
};
#pragma pack()//恢复默认,一般是8

//字节对齐数 按结构塔中最大成员的字节数 和 设置数  取小值
//则按2字节 对齐

int main()
{

    union u a = { 0x9843 };
    printf("1.%c %x
", a.c, a.i);


    a.c = 'B';
    printf("2.%c %x
", a.c, a.i);   


    a.i = 0x0143;
    printf("3.%c 4.%d
", a.c, a.i);   


    //大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位保存在内存的低地址中
    //小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中
    int num = 1;
    char *p = (char*)&num;
    if (*p == 1)
        cout << "小端" << endl;
    else
        cout << "大端" << endl;

    a.i = 1;
    if (a.c == 1)
        cout << "小端" << endl;
    else
        cout << "大端" << endl;

    MyStruct st;
    cout << sizeof(st) << endl; //指定了#pragma pack(2)则为8, 没有则12
    return 0;
}

内存管理

void GetMemory1(char *p)
{
p = (char*)malloc(100);
}

void Test1()
{
char *str = NULL;
GetMemory1(str);
strcpy(str, "hello world");
printf(str);
}

//str一直是空,程序崩溃,p作为形参,是str的副本,申请了内存,但str并未改变

char *GetMemory()
{
char p[] = "hello world";
return p;
}
void Test2()
{
char *str = NULL;
str = GetMemory();
printf(str);
}

可能是乱码

p[]数组为函数内的局部变量,在函数返回后,内存已经被释放

void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
}

void Test3()
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}

打印hello,

未对malloc的内存进行释放

GetMemory中申请内存后应加上if ( *p == NULL ),以进行内存分配失败的处理

void Test4(void)
{
char *str = (char *)malloc(100);
strcpy(str, "hello");
free(str);
if (str != NULL)
{
strcpy(str, "world");
printf(str); 
}
}

可能会打印world,

free(str);之后未将str赋值为NULL,str为野指针

在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。

malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可以用于申请动态内存和释放内存。

对于非内部数据类型对象而言,光用malloc/free无法满足动态对象的要求。

对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。

由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free.

原文地址:https://www.cnblogs.com/xslwm/p/10461568.html