当前位置:   article > 正文

C++面试题_struct可以继承吗

struct可以继承吗

C++里面的一些关键字

1.static

static常规用法

static常规用法补充
static关键字类里面的用法

2.const

const用法

const修饰函数参数和返回值

3.extern

extern的用法

4.volatile

volatile用法

5.四种类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast

四种类型转换

6.struct 与 class 的区别

总结,主要有这么几点不同:

1.struct 是值类型,class 是对象类型

2.struct 不能被继承,class 可以被继承

3.struct 默认的访问权限是public,而class 默认的访问权限是private.

4.struct总是有默认的构造函数,即使是重载默认构造函数仍然会保留。这是因为Struct的构造函数是由编译器自动生成的,但是如果重载构造函数,必需对struct中的变量全部初始化。并且Struct的用途是那些描述轻量级的对象,例如Line,Point等,并且效率比较高。class在没有重载构造函数时有默认的无参数构造函数,但是一被重载些默认构造函数将被覆盖。

5.struct的new和class的new是不同的。struct的new就是执行一下构造函数创建一个新实例再对所有的字段进行Copy。而class则是在堆上分配一块内存然后再执行构造函数,struct的内存并不是在new的时候分配的,而是在定义的时候分配

7.struct 内存对齐问题,sizeof 与 strlen 区别

1.为什么要内存对齐:因为处理器读写数据,并不是以字节为单位,而是以块(2,4,6,8,16字节)为单位进行的,如果不进行内存对齐,本来只需要一次进行的访问,可能要好几次才能完成。
32位cpu一次能最多处理的信息是32bit位,如果你没有指定对齐,我们假设这样的数据结构在内存中存在的情况

typedef strutc test{
    char a;
    int b;
    char c;
} 
  • 1
  • 2
  • 3
  • 4
  • 5

对应的在内存中存放的方式可能是这样(假定32位下):
在这里插入图片描述
那么,这样一来,取得这个int型变量需要经过两次的寻址,拼凑成一个完整的4字节的数。这个过程还涉及到cpu指令集调用和总线的读写操作,如果真是没有对齐的话,效率会差到不知道哪儿去了。
所以这个内存对齐是必须遵守的,为了提高cpu访问效率和速度。

2.内存对齐的原则:

  1. 对于结构体的各个成员,第一个成员的偏移量是0,排列在后面的成员其当前偏移量必须是当前成员类型的整数倍
  2. 结构体内所有数据成员各自内存对齐后,结构体本身还要进行一次内存对齐,保证整个结构体占用内存大小是结构体内最大数据成员的最小整数倍
  3. 如程序中有#pragma pack(n)预编译指令,则所有成员对齐以n字节为准(即偏移量是n的整数倍),不再考虑当前类型以及最大结构体内类型
3
struct S1
{
    char a;        // 1
    char b;        // 1
    int c;          // 4
};
printf("%d\n", sizeof(struct S1));4
struct S2
{
    char a;        // 1
    int  b;        // 4
    char c;       // 1
};
printf("%d\n", sizeof(struct S2));

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在这里插入图片描述
对于s1:a占用一个字节,偏移量是1,b是char型,占一个字节,偏移量1是这一个字节的整数倍,所以b放在a后面,现在偏移量是2,c是int型,占四个字节,2不是4的整数倍,所以在b后面填充两个字节,现在的偏移量就是4,是int类型的整数倍。所以int的起始地址是4。
对于s2:a占用一个字节,偏移量为1,b占四个字节,所以a后面要预留3个字节。放完b后现在的偏移量是8,c占1个字节,直接放在b的后面。而结构体的内存必须为结构体内最大成员的最小整数倍,结构体内最大成员是b,占四个字节,所以结构体的大小必须为4的整数倍,所以c后面要留三个字节大小。

8.union是什么,有什么用?

union的作用

1.this指针

this指针

2.多态特性

1、联编
联编就是把函数名与函数体的程序代码连接(联系)在一起的过程。
静态联编就是在编译阶段完成的联编。静态联编函数调用速度很快。效率高, 但缺乏灵活性;
动态联编是运行阶段完成的联编。动态联编在运行时才能确定调用哪个函数,它降低了程序的运行效率,但增强了程序的灵活性。

2、多态
编译时多态是通过静态联编来实现的。编译时多态性主要是通过函数重载和运算符重载实现的。
运行时多态是通过动态联编实现的。运行时多态性主要是通过虚函数来实现的。

3.类的访问权限:private、protected、public

第一:private,public,protected方法的访问范围.(public继承下)
private: 只能由该类中的函数、其友元函数访问,不能被任何其他访问,该类的对象也不能访问.
protected: 可以被该类中的函数、子类的函数、以及其友元函数访问,但不能被该类的对象访问
public: 可以被该类中的函数、子类的函数、其友元函数访问,也可以由该类的对象访问
第二:类的继承后方法属性变化:
使用private继承,父类的所有方法在子类中变为private;
使用protected继承,父类的protected和public方法在子类中均变为protected;而private方法不变;
使用public继承,父类中的方法属性不发生改变;
在这里插入图片描述
注意:虽然子类无法直接访问基类的private成员,但是子类也继承了父类的私有成员,子类可以通过调用父类的非私有的成员函数调用基类的私有成员

4.C++类内可以定义引用数据成员吗?

可以,必须在初始化列表时就初始化

初始化列表以冒号开始,形式为 变量名(初值),多个变量之间以逗号分隔。
初始化列表的用处在于,它可以对const修饰的常量进行初始化。而若写在大括号中,是在计算阶段赋值,而常量是不能在计算阶段进行赋值的。
初始化列表只能用于构造函数中,无论是普通构造函数还是拷贝构造函数。
成员变量中含有常量时,只能用初始化列表进行初始化。

5.C++类中的默认函数及其特点

C++类里面默认创建的6个函数

6.四大基本函数,构造,析构,拷贝构造,赋值函数

四大基本函数概述

7.虚函数实现动态多态的原理、虚函数与纯虚函数的区别

虚函数与纯虚函数的区别

8.静态与多态:重写、重载、模板

多态

9.为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数

析构函数为什么必须是虚函数

10.虚函数和多态

虚函数和多态

11.虚函数表具体是怎样实现运行时多态的?

多态的实现

12.构造函数能不能抛出异常?析构函数呢?

不建议在构造函数中抛出异常。当构造函数中抛出异常时,析构函数将不会被执行,需要手动释放内存。但是构造函数是可以抛出异常的。
析构函数不应该抛出异常。当析构函数中有一些可能发生的异常时,这时候要把可能发生的异常完全封装在析构函数内部,决不能让它抛出到函数之外。C++标准指明析构函数不能、也不应该抛出异常。
抛出异常详解

13.构造函数可以是虚函数吗?

构造函数不可以是虚函数。因为类的虚函数表指针是在构造函数中初始化的,在虚表指针没有被正确初始化之前,我们不能调用虚函数。

14.构造函数和析构函数可以调用虚函数吗?

构造函数和析构函数也不能调用虚函数,前者是因为虚表指针还没有被初始化,后者是因为虚表指针可能已经被析构了。

STL

1.STL常见面试题

STL常见面试题

vector容器的释放和删除时需要注意的事项

C++11的特性

1.移动构造函数与拷贝构造函数对比

讲讲移动构造函数与拷贝构造函数的区别:移动构造函数是c++11的新特性,移动构造函数传入的参数是一个右值 用&&标出。一般来说左值可以通过使用std:move方法强制转换为右值。首先讲讲拷贝构造函数:拷贝构造函数是先将传入的参数对象进行一次深拷贝,再传给新对象。这就会有一次拷贝对象的开销,并且进行了深拷贝,就需要给对象分配地址空间。而移动构造函数就是为了解决这个拷贝开销而产生的。移动构造函数首先将传递参数的内存地址空间接管,然后将内部所有指针设置为nullptr,并且在原地址上进行新对象的构造,最后调用原对象的的析构函数,这样做既不会产生额外的拷贝开销,也不会给新对象分配内存空间。

而对于指针参数来讲,需要注意的是,移动构造函数是对传递参数进行一次浅拷贝。也就是说如果参数为指针变量,进行拷贝之后将会有两个指针指向同一地址空间,这个时候如果前一个指针对象进行了析构,则后一个指针将会变成野指针,从而引发错误。所以当变量是指针的时候,要将指针置为空,这样在调用析构函数的时候会进行判断指针是否为空,如果为空则不回收指针的地址空间,这样就不会释放掉前一个指针。
区别

2.四种智能指针及底层实现:auto_ptr、unique_ptr、shared_ptr、weak_ptr

四种智能指针

shared_ptr

3.右值引用

右值引用

4.std::move函数

move函数用法

5.lamda表达式

lamda表达式的用法

6.智能指针的底层实现

智能指针底层实现

7.自己定义的类型怎样实现范围for循环

实现范围for循环

内存管理

1.new/delete与malloc/free的区别是什么

区别

2.malloc的原理,另外brk系统调用和mmap系统调用的作用分别是什么?

malloc的底层原理

3.C++的内存管理是怎样的?

内存管理

4.如何判断内存泄漏?

内存总结

5.new一个对象的时候发生了什么

new一个对象时发生了什么

有父类时

其它问题

1.指针与引用的区别

1) 引用必须被初始化,指针不必。

int ival=1024;
int &refval=ival;   //refval指向ival(是ival的另一个名字)
int &refval2;   //报错,引用必须初始化
  • 1
  • 2
  • 3

因为一般在初始化变量时,初始值会被拷贝到新建立的对象中。不过在定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。一旦初始化完成,引用则绑定到它的初始化对象上。不能更改绑定的对象,因此引用必须初始化。

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

2.C 与 C++ 的区别

1.C语言面向过程,C++面向对象
面向过程:面向过程编程就是分析出解决问题的步骤,然后把这些步骤一步一步的实现,使用的时候一个一个的依次调用就可以了。
面向对象::面向对象编程就是把问题抽象成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。

2、后缀名不同

3.返回值
C语言中,如果一个函数没有指定返回值类型,默认返回int类型;C++中,如果一个函数没有返回值则必须指定为void。

4.关键字不同
C99有32个关键字
C++98有63个关键字
一些关键字的细微区别:
(1)struct:在C语言中struct定义的变量中不能有函数,而在C++中可以有函数。
(2)malloc :malloc函数的返回值为void*,在C语言中可以赋值给任意类型的指针,在C++中必须强制类型转换,否则报错。
(3)struct和class:class是对struct的扩展,struct默认的访问权限是public,而class默认的访问权限是private。

5.函数重载
函数重载:函数重载是函数的一种特殊情况,指在同一作用域中,声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数、类型、顺序)必须不同,返回值类型可以相同也可以不同,常用来处理实现功能类似数据类型不同的问题。(C语言没有函数重载,C++支持函数重载)。

6.缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的参。(C语言不支持缺省参数)

3.面向对象的三大特性:封装、继承、多态

1、封装
通过封装将一部分成员隐藏起来,另一部分成员作为类或对象与外部的接口。从而控制数据的访问权限,并且能够减少程序中不同部分之间的相互影响。隐藏对象的属性和接口实现细节,仅仅对外提供接口和方法。
优点:提高安全性,隔离影响。
2、继承
在父类基础上创建派生类,可以通过增加、修改、替换父类成员产生派生类,对父类进行扩充,这种继承性使程序具有可重用性。子类可以从父类中获得同类的本质特征,并且增加个体特征,而不必完全重新定义。
优点:提高代码重用性。

子类会继承父类的哪些数据?
子类会继承父类除了构造函数、拷贝构造函数和析构函数以外所有的非静态成员.
注意:虽然父类的private成员在子类中无法访问到,但是仍然继承到了子类中,这些成员只是被隐藏了.

3、多态
多态体现在两个方面,动态联编和静态联编,分别指 在程序运行时的多态 和 在程序编译时的多态。
动态联编:在子类中 重写 基类的虚函数,使用 基类指针 或者 基类引用 指向子类对象时,可以实现不同的功能。
静态联编:使用 普通的函数重载 或者 函数模板的使用,实现调用同名函数实现不同功能。
优点:提高代码重用性,提高可扩展性

4.内存分区:全局区、堆区、栈区、常量区、代码区

代码区:存放程序的代码,即CPU执行的机器指令,并且是只读的。
常量区:存放常量(程序在运行的期间不能够被改变的量,例如: 10,字符串常量”abcde”, 数组的名字等)
静态区(全局区):静态变量和全局变量的存储区域是一起的,一旦静态区的内存被分配, 静态区的内存直到程序全部结束之后才会被释放
堆区:由程序员调用malloc()函数来主动申请的,需使用free()函数来释放内存,若申请了堆区内存,之后忘记释放内存,很容易造成内存泄漏
栈区:存放函数内的局部变量,形参和函数返回值。栈区之中的数据的作用范围过了之后,系统就会回收自动管理栈区的内存(分配内存 , 回收内存),不需要开发人员来手动管理。栈区就像是一家客栈,里面有很多房间,客人来了之后自动分配房间,房间里的客人可以变动,是一种动态的数据变动。
在这里插入图片描述

5.深拷贝与浅拷贝的区别

深拷贝与浅拷贝

6.数组和指针的区别

数组和指针的区别

7.野指针是什么

什么是野指针

垂悬指针:指针正常初始化,曾指向一个对象,该对象被销毁了,但是指针未制空,那么就成了悬空指针。

8.函数指针

函数指针

9.fork函数

fork函数

10.strcpy和strlen

它们之间的区别

11.++i和i++的区别

++i和i++的区别与实现

12.写个函数在main函数执行前先运行

全局变量和attribute

13.C++里是怎么定义常量的?常量存放在内存的哪个位置?

怎么定义常量

对于局部常量,存放在栈区;

对于全局常量,放在全局区/静态区

字面值常量,比如字符串,放在常量区。

14.const修饰成员函数的目的是什么?

const修饰函数成员

15.隐式类型转换

隐式类型转换
隐式类型转换2

16.C++函数栈空间的最大值

栈空间的大小

17.extern“C”

extern的用法
Extern “C”是由C++提供的一个连接交换指定符号,用于告诉C++这段代码是C函数。这是因为C++编译后库中函数名会变得很长,与C生产的不一致,造成C++不能直接调用C函数,加上Extern “C”后,C++就能直接调用C函数了。(实现C与C++的混合编程)表示用到C语言中的变量或函数

18.C语言是怎么进行函数调用的?

懂了就不用看下面的

C语言栈帧
怎么进行函数调用

19.C++如何处理返回值?

三种返回值

20.一个C++源文件从文本到可执行文件经历的过程?

源文件执行过程

21.什么时候会发生段错误

段错误1
段错误2

22.共享内存相关api

操作系统共享内存

23.宏定义和内联函数的区别

1.内联函数的调用是传参,宏定义只是简单的文本替换
2.内联函数是在编译时展开的,宏定义在预处理阶段就进行替换了(因为虚函数是在运行时生效的,所以虚函数不能声明为内联的)
3.内联函数有类型检测更加的安全,宏定义没有类型检测
4.内联函数在运行时可调式,宏定义不可以
5.内联函数可以访问类的成员变量,宏不可以
6.在类中声明同时定义的成员函数,自动转化为内联函数。

24.内联函数和宏定义的优点与缺点

宏的缺点:
1.宏没有类型检测,不安全
2.宏是在预处理时进行简单文本替换,并不是简单的参数传递(很难处理一些特定情况。例如:Add(z++))
3.使代码变长
4.宏不能进行调试

宏的优点:
1.提高程序可读性,方便进行修改
2.使用带参数的宏定义既可以完成函数调用的功能,又可以避免函数的出栈入栈操作,减少系统开销,提高运行效率
3.宏是由预处理器处理的,通过字符串操作可以完成很多编译器无法实现的功能,比如##连接符

内联函数的优点:
1.直接将代码插入调用处,减少普通函数调用时的资源消耗
2.有参数检测更安全
3.inline关键字只是对编译器的一个定义,如果函数不符合内联函数的标准,编译器就会把这个函数当成普通函数

内联函数的缺点:
1.使代码长度变长,文件变大

25.重载的匹配规则

重载的匹配

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/714668
推荐阅读
相关标签
  

闽ICP备14008679号