C++常见问题总结
C++ 常见问题总结
学习C++的过程中总是问题多多,这⾥总结⼀下
1. 变量声明和定义区别?
1. 声明仅仅是把变量的声明的位置及类型提供给编译器,并不分配内存空间;定义要在定义的地⽅为其分配存储空间。
2. 相同变量可以再多处声明(外部变量extern),但只能在⼀处定义。
2. “零值⽐较”?
1. bool类型:if(flag)
2. int类型:if(flag == 0)
3. 指针类型:if(flag == null)
4. float类型:if((flag >= -0.000001) && (flag <= 0. 000001))
3. strlen和sizeof区别?
1. sizeof是运算符,并不是函数,结果在编译时得到⽽⾮运⾏中获得;strlen是字符处理的库函数。
2. sizeof参数可以是任何数据的类型或者数据(sizeof参数不退化);strlen的参数只能是字符指针且结尾是’\0’的字符串。
sizeof 指针3. 因为sizeof值在编译时确定,所以不能⽤来得到动态分配(运⾏时分配)存储空间的⼤⼩。
4. 同⼀类不同对象可以互相赋值吗?
1. 可以,但含有指针成员时需要注意。
2. 对⽐类的对象赋值时深拷贝和浅拷贝。
5. 结构体内存对齐问题?
1. 结构体内成员按照声明顺序存储,第⼀个成员地址和整个结构体地址相同。
2. 未特殊说明时,按结构体中size最⼤的成员对齐(若有double成员),按8字节对齐。
6. static作⽤是什么?在C和C++中有何区别?
1. static可以修饰局部变量(静态局部变量)、全局变量(静态全局变量)和函数,被修饰的变量存储位置在静态区。对于静态局
部变量,相对于⼀般局部变量其⽣命周期长,直到程序运⾏结束⽽⾮函数调⽤结束,且只在第⼀次被调⽤时定义;对于静态全局变量,相对于全局变量其可见范围被缩⼩,只能在本⽂件中可见;修饰函数时作⽤和修饰全局变量相同,都是为了限定访问域。
2. C++的static除了上述两种⽤途,还可以修饰类成员(静态成员变量和静态成员函数),静态成员变量和静态成员函数不属于任
何⼀个对象,是所有类实例所共有。
3. static的数据记忆性可以满⾜函数在不同调⽤期的通信,也可以满⾜同⼀个类的多个实例间的通信。
4. 未初始化时,static变量默认值为0。
7. 结构体和类的区别?
1. 结构体的默认限定符是public;类是private。
2. 结构体不可以继承,类可以。 C++中结构体也可以继承。
8. malloc和new的区别?
1. malloc和free是标准库函数,⽀持覆盖;new和delete是运算符,并且⽀持重载。
2. malloc仅仅分配内存空间,free仅仅回收空间,不具备调⽤构造函数和析构函数功能,⽤malloc分配空间存储类的对象存在风
险;new和delete除了分配回收功能外,还会调⽤构造函数和析构函数。
3. malloc和free返回的是void类型指针(必须进⾏类型转换),new和delete返回的是具体类型指针。
9. 指针和引⽤区别?
1. 引⽤只是别名,不占⽤具体存储空间,只有声明没有定义;指针是具体变量,需要占⽤存储空间。
2. 引⽤在声明时必须初始化为另⼀变量,⼀旦出现必须为typename refname &varname形式;指针声明和定义可以分开,可以
先只声明指针变量⽽不初始化,等⽤到时再指向具体变量。
3. 引⽤⼀旦初始化之后就不可以再改变(变量可以被引⽤为多次,但引⽤只能作为⼀个变量引⽤);
指针变量可以重新指向别的变
量。
4. 不存在指向空值的引⽤,必须有具体实体;但是存在指向空值的指针。
10. 宏定义和函数有何区别?
1. 宏在编译时完成替换,之后被替换的⽂本参与编译,相当于直接插⼊了代码,运⾏时不存在函数调⽤,执⾏起来更快;函数调⽤
在运⾏时需要跳转到具体调⽤函数。
2. 宏函数属于在结构中插⼊代码,没有返回值;函数调⽤具有返回值。
3. 宏函数参数没有类型,不进⾏类型检查;函数参数具有类型,需要检查类型。
4. 宏函数不要在最后加分号。
11. 宏定义和const区别?
1. 宏替换发⽣在编译阶段之前,属于⽂本插⼊替换;const作⽤发⽣于编译过程中。
2. 宏不检查类型;const会检查数据类型。
3. 宏定义的数据没有分配内存空间,只是插⼊替换掉;const定义的变量只是值不能改变,但要分配内存空间。
12. 宏定义和typedef区别?
1. 宏主要⽤于定义常量及书写复杂的内容;typedef主要⽤于定义类型别名。
2. 宏替换发⽣在编译阶段之前,属于⽂本插⼊替换;typedef是编译的⼀部分。
3. 宏不检查类型;typedef会检查数据类型。
4. 宏不是语句,不在在最后加分号;typedef是语句,要加分号标识结束。
5. 注意对指针的操作,typedef char * p_char和#define p_char char *区别巨⼤。
13. 宏定义和内联函数(inline)区别?
1. 在使⽤时,宏只做简单字符串替换(编译前)。⽽内联函数可以进⾏参数类型检查(编译时),且具有返回值。
2. 内联函数本⾝是函数,强调函数特性,具有重载等功能。
3. 内联函数可以作为某个类的成员函数,这样可以使⽤类的保护成员和私有成员。⽽当⼀个表达式涉及到类保护成员或私有成员
时,宏就不能实现了。
14. 条件编译#ifdef, #else, #endif作⽤?
14. 条件编译#ifdef, #else, #endif作⽤?
1. 可以通过加#define,并通过#ifdef来判断,将某些具体模块包括进要编译的内容。
2. ⽤于⼦程序前加#define DEBUG⽤于程序调试。
3. 应对硬件的设置(机器类型等)。
4. 条件编译功能if也可实现,但条件编译可以减少被编译语句,从⽽减少⽬标程序⼤⼩。
15. 区别以下⼏种变量?
const int a;
int const a;
const int *a;
int *const a;
1. int const a和const int a均表⽰定义常量类型a。
2. const int a,其中a为指向int型变量的指针,const在 左侧,表⽰a指向不可变常量。(看成const (*a),对引⽤加const)
3. int *const a,依旧是指针类型,表⽰a为指向整型数据的常指针。(看成const(a),对指针const)
16. volatile有什么作⽤?
1. volatile定义变量的值是易变的,每次⽤到这个变量的值的时候都要去重新读取这个变量的值,⽽不是读寄存器内的备份。
2. 该关键字的作⽤是防⽌优化编译器把变量从内存装⼊CPU寄存器中。
3. volatile 的意思是让编译器每次操作该变量时⼀定要从内存中真正取出,⽽不是使⽤已经存在寄存器
中的值。
4. 多线程中被⼏个任务共享的变量需要定义为volatile类型,避免⼀个线程使⽤寄存器中的变量,⽽另⼀个线程使⽤内存中的变
量,造成程序错误。
17. 什么是常引⽤?
1. 常引⽤可以理解为常量指针,形式为const typename & refname = varname。
2. 常引⽤下,原变量值不会被别名所修改。
3. 原变量的值可以通过原名修改。
4. 常引⽤通常⽤作只读变量别名或是形参传递。
18. 区别以下指针类型?
int *p[10]
int (*p)[10]
int *p(int)
int (*p)(int)
1. int *p[10]表⽰指针数组,强调数组概念,是⼀个数组变量,数组⼤⼩为10,数组内每个元素都是指向int类型的指针变量。
2. int (*p)[10]表⽰数组指针,强调是指针,只有⼀个变量,是指针类型,不过指向的是⼀个int类型的数组,这个数组⼤⼩是10。
3. int p(int)是函数声明,函数名是p,参数是int类型的,返回值是int 类型的。
4. int (*p)()是函数指针,强调是指针,该指针指向的函数具有int类型参数,并且返回值是int类型的。
19. 常量指针和指针常量区别?
1. 常量指针是⼀个指针,读成常量的指针,指向⼀个只读变量。如int const *p或const int *p。
2. 指针常量是⼀个不能给改变指向的指针。如int *const p。
2. 指针常量是⼀个不能给改变指向的指针。如int *const p。
20. a和&a有什么区别?
假设数组int a[10];
int (*p)[10] = &a;
1. a是数组名,是数组⾸元素地址,+1表⽰地址值加上⼀个int类型的⼤⼩,如果a的值是0x00000001,加1操作后变为
0x00000005。*(a + 1) = a[1]。
2. &a是数组的指针,其类型为int (*)[10](就是前⾯提到的数组指针),其加1时,系统会认为是数组⾸地址加上整个数组的偏移
(10个int型变量),值为数组a尾元素后⼀个元素的地址。
3. 若(int )p ,此时输出 *p时,其值为a[0]的值,因为被转为int 类型,解引⽤时按照int类型⼤⼩来读取。
21. 数组名和指针(这⾥为指向数组⾸元素的指针)区别?
1. ⼆者均可通过增减偏移量来访问数组中的元素。
2. 数组名不是真正意义上的指针,可以理解为常指针,所以数组名没有⾃增、⾃减等操作。
3. 当数组名当做形参传递给调⽤函数后,就失去了原有特性,退化成⼀般指针,多了⾃增、⾃减操作,但sizeof运算符不能再得到
原数组的⼤⼩了。
22. 野指针是什么?
1. 也叫空悬指针,不是指向null的指针,是指向垃圾内存的指针。
2. 产⽣原因及解决办法:
1. 指针变量未及时初始化 => 定义指针变量及时初始化,要么置空。
2. 指针free或delete之后没有及时置空 => 释放操作后⽴即置空。
23. 堆和栈的区别?
1. 申请⽅式不同。
1. 栈由系统⾃动分配。
2. 堆由程序员⼿动分配。
2. 申请⼤⼩限制不同。
1. 栈顶和栈底是之前预设好的,⼤⼩固定,可以通过ulimit -a查看,由ulimit -s修改。
2. 堆向⾼地址扩展,是不连续的内存区域,⼤⼩可以灵活调整。
3. 申请效率不同。
1. 栈由系统分配,速度快,不会有碎⽚。
2. 堆由程序员分配,速度慢,且会有碎⽚。
24. delete和delete[]区别?
1. delete只会调⽤⼀次析构函数。
2. delete[]会调⽤数组中每个元素的析构函数。
⾯向对象基础
能够准确理解下⾯这些问题是从C程序员向C++程序员进阶的基础。当然了,这只是⼀部分。
1. ⾯向对象三⼤特性?
1. 封装性:数据和代码捆绑在⼀起,避免外界⼲扰和不确定性访问。
2. 继承性:让某种类型对象获得另⼀个类型对象的属性和⽅法。
3. 多态性:同⼀事物表现出不同事物的能⼒,即向不同对象发送同⼀消息,不同的对象在接收时会产⽣不同的⾏为(重载实现编译
时多态,虚函数实现运⾏时多态)。
2. public/protected/private的区别?
1. public的变量和函数在类的内部外部都可以访问。
2. protected的变量和函数只能在类的内部和其派⽣类中访问。
3. private修饰的元素只能在类内访问。
3. 对象存储空间?
1. ⾮静态成员的数据类型⼤⼩之和。
2. 编译器加⼊的额外成员变量(如指向虚函数表的指针)。
3. 为了边缘对齐优化加⼊的panding。
4. C++空类有哪些成员函数?
1. ⾸先,空类⼤⼩为1字节。
2. 默认函数有:
1. 构造函数
2. 析构函数
3. 拷贝构造函数
4. 赋值运算符
5. 构造函数能否为虚函数,析构函数呢?
1. 析构函数:
1. 析构函数可以为虚函数,并且⼀般情况下基类析构函数要定义为虚函数。
2. 只有在基类析构函数定义为虚函数时,调⽤操作符delete销毁指向对象的基类指针时,才能准确调⽤派⽣类的析构函数
(从该级向上按序调⽤虚函数),才能准确销毁数据。
3. 析构函数可以是纯虚函数,含有纯虚函数的类是抽象类,此时不能被实例化。但派⽣类中可以根据⾃⾝需求重新改写基类
中的纯虚函数。
2. 构造函数:
1. 构造函数不能定义为虚函数,不仅如此,构造函数中还不能调⽤虚函数。因为那样实际执⾏的是⽗类对应的函数,因为⾃
⼰还没有构造好(构造顺序先基类再派⽣类)。
6. 构造函数调⽤顺序,析构函数呢?

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。