C/C++面试题集锦(一)
*/-->
C/C++面试题集锦(一)
- 在类的头文件中进行声明然后在定义文件中实现有什么意义?
- 一方面使类的实现只编译一次,提高编译效率;另一方面可以实现类的接口和实现的分离,利于维护
- 在类的声明内部实现成员函数的函数体
- 这种成员函数自动成为内联函数,这种函数在编译阶段只要是用到的地方都会进行代码替换
- 成员函数通过什么来区分不同的对象
- 通过普通成员函数隐含的this指针来区分不同对象。一个类的不同对象之间代码是共享的,只有数据是不同的,this指针指向这些不同的数据内存位置的首地址。
- 拷贝构造函数的使用情形
- a.在使用对象去初始化同类的另一个对象时 b.函数调用时使用类对象作为形参时 c.函数返回值返回一个类对象时
- 什么时候必须重写拷贝构造函数
- 当类的成员需要对指针进行深拷贝时,需要在用到的构造函数内进行动态内存分配,相应的要在析构函数内进行动态内存释放
- 构造函数调用的顺序
- a.调用基类的构造函数 b.按声明中的顺序对类的数据成员进行初始化 c.调用本类自己的构造函数
- 什么情况下必须用到初始化成员列表
- a. 类的成员具有一经初始化便不能修改的特性如常属性和引用 b. 类的成员是另一个类,且这个类没有默认的构造函数(即需要传参数)
- 类的静态成员函数存在的意义
- 相比普通成员函数不需要生成对象、没有this指针的开销,效率稍高;为无需实例化的函数提供了一种贴切的实现方式。
- 在类外有什么办法访问类的非共有成员
- 友元、继承和公有成员函数
- 抽象类
- 不能用来建立对象只能用作继承的基类,具体的是成员函数至少有一个是纯虚函数(声明中=0,而不管这个函数是否有实现代码)
- 运算符重载的意义
- 为自定义的数据类型提供与语言内置的类型提供一致的数据操作接口
- 不允许重载的5个运算符
- .*、::、sizeof、?:、.
- 流运算符为什么不能通过成员函数重载?一般怎么解决
- 在类内对运算符进行重载要求运算符的第一个操作数必须是本类的对象,因为流对象属于标准库的类,无法实现在标准库中对各种自定义的类的流操作进行重载。一般通过自定义类的友元函数来实现类流操作符的重载
- 赋值运算符和拷贝构造函数有什么区别和联系
- 他们都是通过类的一个对象来建立起类的另一个对象,但拷贝构造函数涉及到对象的构造,赋值运算符不需要建立对象
- 什么情况下调用类的析够函数
- 对象生命周期结束的时候,一般是在离对象最近的右花括号处
- 类的对象之间如何实现数据的共享
- 通过类的静态成员变量来实现,静态成员变量有自己独立的存储空间,数据为整个类的所有成员所共享,都能访问。
- 类的数据成员初始化的顺序
- 初始化的顺序由他们在类的声明中的顺序决定的。
- virtual函数实现多态的时候子类中的覆盖函数这个关键字是否是必须的?
- virtual关键字会被隐形继承,即使子类中不加这个关键字也能实现多态
- 函数重载与虚函数在实现函数的多态上有什么区别
- 函数重载是通过函数签名不同(函数名、函数参数个数、函数参数的类型)在编译期间实现的静态的多态;虚函数是通过类之间的继承关系和函数在子类中被覆盖,
- 友元关系的特性
- 单向性、非传递性、不能继承的。
- 构造函数和析构函数能否重载?
- 构造函数可以有多个且参数不同,可以重载;析构函数只能有一个所以不能重载,而且他没有参数。
- 虚函数的实现
- 虚函数表(虚表指针)???
- main函数执行前还会执行什么代码
- 全局域的对象的构造函数会在main函数执行前执行
- 当一个类中没有声明任何变量和函数时,sizeof 类是多少,为什么?
- 大小是1,是为了在程序中给不同的对象分配不同的内存地址,来区分类的不同对象。
- delete 与 delete[] 的区别
- delete只调用一次析构函数,后者会调用每一个对象的析构函数。
- 基类和派生类析构和构造函数的调用顺序
- 在对象创建过程中基类的构造函数会被先调用,然后是本类的构造函数;析构函数的调用过程相反。在基类的构造函数工作的过程中,本类的对象没有被完全建立,本类的信息是不完整的,同理,在析构过程中,基类的析构函数工作过程中,本类的信息也已经被销毁了。
- 继承的优缺点
- 是代码复用的一种方式,提供一定程度上的灵活性,优点也成为了限制。
- 类的构造和析构函数什么时候被调用,被谁调用?
- 分别在类的生命周期开始和结束时被系统自动调用。有时也可以由程序员手动调用。
- 预编译
- 多个模块,不经常改动。
- c++中多态的实现
- a.静态多态,在编译期间确定(函数模板和函数重载,注意函数缺省参数),b.动态多态,在运行期间确定(虚函数,覆盖,指针或引用)
- c++中四大特性的作用
- 封装使代码能够模块化,继承使代码易于扩展,而多态是为了接口的一致和重用,抽象???(数据抽象、算法抽象)类的概念,模板的概念
- 普通函数、静态函数、友元函数为什么不能为虚函数
- 普通函数会在编译时确定代码,无法实现动态多态;类的静态成员函数在基类和所有子类中只有一份拷贝,友元函数没有继承的特性,也无法实现动态多态,所以没必要支持虚函数
- 内联函数为什么不能为虚函数
- 内联函数是为了在编译期间将代码展开,虚函数是为了在运行时支持执行多个不同的代码分支,从概念上就是不兼容的。
- 构造函数为什么不能是虚函数
- a.虚函数的实现需要虚表的支持,此时虚表尚未建立 b.构造函数无法通过指针或引用来调用,所以不必设置为虚函数 c.虚函数的实现需要通过指针或引用确定对象的类型,构造函数被调用时还没有完整的对象,无法确定对象类型,所以无法设置为虚函数。
- 为什么基类的析构函数最好设置为虚函数?
- 因为动态多态性支持通过基类指针或引用来使用派生类对象,此时当派生类对象需要析构时,只有析构函数是虚函数时,才能正确的析构
- 类的私有成员可以被哪些函数访问
- 可以被本类的成员函数和友元访问
- 类的保护成员可以被那些函数访问
- 可以被本类的成员函数和友元和公有和保护派生方式派生出来的类访问
- 常引用
- 既提高程序运行的效率又要保护传递给函数的数据不再函数中被改变
- 指针和引用的区别
- 引用必须被初始化,初始化后就不可以改变而指针不必,指针可以指向空值,引用不可以。
- switch后的表达式不可以为什么类型
- 可以为整型、字符、布尔、枚举类型;不可以为浮点型数据。
- 如何引用一个定义过的全局变量
- a. 全局变量在头文件内,可以直接引用头文件后使用 b. 如果在其他源文件中定义的全局变量,可以使用extern关键字使用此全局变量。
- 频繁使用的短小函数在c/c++语言中如何处理
- 在c语言中使用宏定义,在c++语言中使用内联函数。
- 内存分配的三种方式
- 静态存储区分配在编译期间确定、栈上分配、堆上动态分配。
- extern "C"有什么用
- 用来在c++程序程序中声明特定的程序语句或语句块按照c语言的函数命名规则进行编译。
- 使用#define和const定义常量有什么区别
- #define是C语言预处理器的语法关键字,在编译期间只执行常量替换;const是C++语言定义常变量的方法,它具有类型,有内存分配,可以用sizeof测试出长度。
- struct和class的区别
- struct成员默认访控属性是公有的,而class的默认访控属性是私有的。
- 局部变量和全局变量能否同名?
- 可以,局部变量会屏蔽全局变量;要访问全局变量需要使用::域运算符。
- assert宏
- 用于调试程序,以避免程序中出现明显错误的或非法的数据,可以使用
#define NDEBUG
来在特定版本的程序中禁止使用assert断言 - windows消息队列由哪几部分组成
- a. 系统消息队列,由操作系统负责将消息投放到特定的应用程序的消息队列中 b. 应用程序消息循环,每个应用程序都有各自的消息队列,在应用程序消息循环中,不断地从自己的消息队列中取出消息并进行特定的消息的处理,然后再将消息交由windows操作系统来调用相应的窗口处理函数 c. 窗口处理函数,除了在消息循环中已经处理的消息外,其他的消息都会由操作系统调用相应的窗口处理函数来处理不同的消息。
- sendmessage 和 postmessage有什么区别
- sendmessage是直接将消息过程跳过消息队列和消息循环直接交由特定的窗口处理函数进行处理,并等待消息处理结束返回。postmessage是将消息放入应用程序消息队列中,但是并不等待消息处理结束而是即刻返回。
- 消息映射
- 是在mfc类中,程序员通过将系统消息映射到类的成员函数从而实现mfc类对操作系统消息的各种处理。
- 构成win32 api的三个动态链接库是什么
- kernel32.dll、user32.dll和gdi32.dll
- windows消息分为几类,并对各个类进行简要的介绍?
- a.窗口消息:与窗口相关的消息,除
WM_COMMAND
b. 命令消息:用于处理用户请求,以WM_COMMAND
表示的消息 c. 控件通知消息:统一由WM_NOTIFY
处理 - 在类的头文件中进行声明然后在定义文件中实现有什么意义?
- 一方面使类的实现只编译一次,提高编译效率;另一方面可以实现类的接口和实现的分离,利于维护
- 在类的声明内部实现成员函数的函数体
- 这种成员函数自动成为内联函数,这种函数在编译阶段只要是用到的地方都会进行代码替换
- 成员函数通过什么来区分不同的对象
- 通过普通成员函数隐含的this指针来区分不同对象。一个类的不同对象之间代码是共享的,只有数据是不同的,this指针指向这些不同的数据内存位置的首地址。
- 拷贝构造函数的使用情形
- a.在使用对象去初始化同类的另一个对象时 b.函数调用时使用类对象作为形参时 c.函数返回值返回一个类对象时
- 什么时候必须重写拷贝构造函数
- 当类的成员需要对指针进行深拷贝时,需要在用到的构造函数内进行动态内存分配,相应的要在析构函数内进行动态内存释放
- 构造函数调用的顺序
- a.调用基类的构造函数 b.按声明中的顺序对类的数据成员进行初始化 c.调用本类自己的构造函数
- 什么情况下必须用到初始化成员列表
- a. 类的成员具有一经初始化便不能修改的特性如常属性和引用 b. 类的成员是另一个类,且这个类没有默认的构造函数(即需要传参数)
- 类的静态成员函数存在的意义
- 相比普通成员函数不需要生成对象、没有this指针的开销,效率稍高;为无需实例化的函数提供了一种贴切的实现方式。
- 在类外有什么办法访问类的非共有成员
- 友元、继承和公有成员函数
- 抽象类
- 不能用来建立对象只能用作继承的基类,具体的是成员函数至少有一个是纯虚函数(声明中=0,而不管这个函数是否有实现代码)
- 运算符重载的意义
- 为自定义的数据类型提供与语言内置的类型提供一致的数据操作接口
- 不允许重载的5个运算符
- .*、::、sizeof、?:、.
- 流运算符为什么不能通过成员函数重载?一般怎么解决
- 在类内对运算符进行重载要求运算符的第一个操作数必须是本类的对象,因为流对象属于标准库的类,无法实现在标准库中对各种自定义的类的流操作进行重载。一般通过自定义类的友元函数来实现类流操作符的重载
- 赋值运算符和拷贝构造函数有什么区别和联系
- 他们都是通过类的一个对象来建立起类的另一个对象,但拷贝构造函数涉及到对象的构造,赋值运算符不需要建立对象
- 什么情况下调用类的析够函数
- 对象生命周期结束的时候,一般是在离对象最近的右花括号处
- 类的对象之间如何实现数据的共享
- 通过类的静态成员变量来实现,静态成员变量有自己独立的存储空间,数据为整个类的所有成员所共享,都能访问。
- 类的数据成员初始化的顺序
- 初始化的顺序由他们在类的声明中的顺序决定的。
- virtual函数实现多态的时候子类中的覆盖函数这个关键字是否是必须的?
- virtual关键字会被隐形继承,即使子类中不加这个关键字也能实现多态
- 函数重载与虚函数在实现函数的多态上有什么区别
- 函数重载是通过函数签名不同(函数名、函数参数个数、函数参数的类型)在编译期间实现的静态的多态;虚函数是通过类之间的继承关系和函数在子类中被覆盖,
- 友元关系的特性
- 单向性、非传递性、不能继承的。
- 构造函数和析构函数能否重载?
- 构造函数可以有多个且参数不同,可以重载;析构函数只能有一个所以不能重载,而且他没有参数。
- 虚函数的实现
- 虚函数表(虚表指针)???
- main函数执行前还会执行什么代码
- 全局域的对象的构造函数会在main函数执行前执行
- 当一个类中没有声明任何变量和函数时,sizeof 类是多少,为什么?
- 大小是1,是为了在程序中给不同的对象分配不同的内存地址,来区分类的不同对象。
- delete 与 delete[] 的区别
- delete只调用一次析构函数,后者会调用每一个对象的析构函数。
- 基类和派生类析构和构造函数的调用顺序
- 在对象创建过程中基类的构造函数会被先调用,然后是本类的构造函数;析构函数的调用过程相反。在基类的构造函数工作的过程中,本类的对象没有被完全建立,本类的信息是不完整的,同理,在析构过程中,基类的析构函数工作过程中,本类的信息也已经被销毁了。
- 继承的优缺点
- 是代码复用的一种方式,提供一定程度上的灵活性,优点也成为了限制。
- 类的构造和析构函数什么时候被调用,被谁调用?
- 分别在类的生命周期开始和结束时被系统自动调用。有时也可以由程序员手动调用。
- 预编译
- 多个模块,不经常改动。
- c++中多态的实现
- a.静态多态,在编译期间确定(函数模板和函数重载,注意函数缺省参数),b.动态多态,在运行期间确定(虚函数,覆盖,指针或引用)
- c++中四大特性的作用
- 封装使代码能够模块化,继承使代码易于扩展,而多态是为了接口的一致和重用,抽象???(数据抽象、算法抽象)类的概念,模板的概念
- 普通函数、静态函数、友元函数为什么不能为虚函数
- 普通函数会在编译时确定代码,无法实现动态多态;类的静态成员函数在基类和所有子类中只有一份拷贝,友元函数没有继承的特性,也无法实现动态多态,所以没必要支持虚函数
- 内联函数为什么不能为虚函数
- 内联函数是为了在编译期间将代码展开,虚函数是为了在运行时支持执行多个不同的代码分支,从概念上就是不兼容的。
- 构造函数为什么不能是虚函数
- a.虚函数的实现需要虚表的支持,此时虚表尚未建立 b.构造函数无法通过指针或引用来调用,所以不必设置为虚函数 c.虚函数的实现需要通过指针或引用确定对象的类型,构造函数被调用时还没有完整的对象,无法确定对象类型,所以无法设置为虚函数。
- 为什么基类的析构函数最好设置为虚函数?
- 因为动态多态性支持通过基类指针或引用来使用派生类对象,此时当派生类对象需要析构时,只有析构函数是虚函数时,才能正确的析构
- 类的私有成员可以被哪些函数访问
- 可以被本类的成员函数和友元访问
- 类的保护成员可以被那些函数访问
- 可以被本类的成员函数和友元和公有和保护派生方式派生出来的类访问
- 常引用
- 既提高程序运行的效率又要保护传递给函数的数据不再函数中被改变
- 指针和引用的区别
- 引用必须被初始化,初始化后就不可以改变而指针不必,指针可以指向空值,引用不可以。
- switch后的表达式不可以为什么类型
- 可以为整型、字符、布尔、枚举类型;不可以为浮点型数据。
- 如何引用一个定义过的全局变量
- a. 全局变量在头文件内,可以直接引用头文件后使用 b. 如果在其他源文件中定义的全局变量,可以使用extern关键字使用此全局变量。
- 频繁使用的短小函数在c/c++语言中如何处理
- 在c语言中使用宏定义,在c++语言中使用内联函数。
- 内存分配的三种方式
- 静态存储区分配在编译期间确定、栈上分配、堆上动态分配。
- extern "C"有什么用
- 用来在c++程序程序中声明特定的程序语句或语句块按照c语言的函数命名规则进行编译。
- 使用#define和const定义常量有什么区别
- #define是C语言预处理器的语法关键字,在编译期间只执行常量替换;const是C++语言定义常变量的方法,它具有类型,有内存分配,可以用sizeof测试出长度。
- struct和class的区别
- struct成员默认访控属性是公有的,而class的默认访控属性是私有的。
- 局部变量和全局变量能否同名?
- 可以,局部变量会屏蔽全局变量;要访问全局变量需要使用::域运算符。
- assert宏
- 用于调试程序,以避免程序中出现明显错误的或非法的数据,可以使用
#define NDEBUG
来在特定版本的程序中禁止使用assert断言 - windows消息队列由哪几部分组成
- a. 系统消息队列,由操作系统负责将消息投放到特定的应用程序的消息队列中 b. 应用程序消息循环,每个应用程序都有各自的消息队列,在应用程序消息循环中,不断地从自己的消息队列中取出消息并进行特定的消息的处理,然后再将消息交由windows操作系统来调用相应的窗口处理函数 c. 窗口处理函数,除了在消息循环中已经处理的消息外,其他的消息都会由操作系统调用相应的窗口处理函数来处理不同的消息。
- sendmessage 和 postmessage有什么区别
- sendmessage是直接将消息过程跳过消息队列和消息循环直接交由特定的窗口处理函数进行处理,并等待消息处理结束返回。postmessage是将消息放入应用程序消息队列中,但是并不等待消息处理结束而是即刻返回。
- 消息映射
- 是在mfc类中,程序员通过将系统消息映射到类的成员函数从而实现mfc类对操作系统消息的各种处理。
- 构成win32 api的三个动态链接库是什么
- kernel32.dll、user32.dll和gdi32.dll
- windows消息分为几类,并对各个类进行简要的介绍?
- a.窗口消息:与窗口相关的消息,除
WM_COMMAND
b. 命令消息:用于处理用户请求,以WM_COMMAND
表示的消息 c. 控件通知消息:统一由WM_NOTIFY
表示 d.用户自定义消息 - windows如何自定义消息
- 使用
WM_USER
和WM_APP
来自定义消息 - 怎么消除多重继承中的二义性
- a.使用成员限定符 b.使用虚基类
- 运行时多态的条件
- a.继承 b.基类虚函数在子类中被重写 c.使用基类指针或引用指向子类对象
- MFC中大部分类是从哪个类中继承而来
- CObject类->CCmdTarget类
- c++类成员函数重载、覆盖和隐藏的区别
- 重载的条件(3个)、在基类和派生类的同名函数之间的关系除了覆盖之外都是隐藏关系。覆盖的条件(有继承关系的父子类之间的同名函数,如果参数相同,返回值协变且基类函数有virtual关键字的话,则同名函数之间构成了覆盖关系)。
- 如何打印出当前源文件的文件名和行号
-
__FILE__
和__LINE__