面向对象的程序设计思想是什么?
答:把数据结构和对数据结构进行操作的方法封装形成一个个的对象。
在头文件中进行类的声明,在对应的实现文件中进行类的定义有什么意义?
答:这样可以提高编译效率,因为分开的话只需要编译一次生成对应的.obj文件后,再次应用该类的地方,这个类就不会被再次编译,从而大大的提高了编译效率。
在类的内部定义成员函数的函数体,这种函数会具备那种属性?
答:这种函数会自动为内联函数,这种函数在函数调用的地方在编译阶段都会进行代码替换。
成员函数通过什么来区分不同对象的成员数据?为什么它能够区分?
答:通过this指针指向对象的首地址来区分的。(调用成员函数默认会传this指针)
C++编译器自动为类产生的四个缺省函数是什么?
答:默认构造函数,拷贝构造函数,析构函数,赋值函数。
拷贝构造函数在哪几种情况下会被调用?
答:
1.当类的一个对象去初始化该类的另一个对象时;
2.如果函数的形参是类的对象,调用函数进行形参和实参结合时;
3.如果函数的返回值是类对象,函数调用完成返回时。
构造函数与普通函数相比在形式上有什么不同?(构造函数的作用,它的声明形式来分析)
答:构造函数是类的一种特殊成员函数,一般情况下,它是专门用来初始化对象成员变量的。
构造函数的名字必须与类名相同,它不具有任何类型,不返回任何值。
什么时候必须重写拷贝构造函数?
答:当构造函数涉及到动态存储分配空间时,要自己写拷贝构造函数,并且要深拷贝。
构造函数的调用顺序是什么?
答:
1.先调用父类构造函数
2.按声明顺序 初始化成员(成员变量是类)
3.最后调用自己的构造函数。
哪几种情况必须用到初始化成员列表?
答:类的常量成员或引用成员需要初始化;(常量不能赋值,引用必须初始化)
有成员变量是类,且没有无参构造函数。
子类希望 父类使用带参数的构造函数初始化父类(如果初始化列表没有指定,默认使用无参)
什么是常对象?
答:常对象是指在任何场合都不能对其成员的值进行修改的对象。
静态函数存在的意义?
答:静态成员需要类外初始化,但是静态私有成员在类外不能被访问,可通过类的静态函数来访问;
构造函数私有,只能通过静态成员函数来调用构造函数。(像单例提供静态函数getinstance,里面调用构造函数创建静态局部变量)
静态变量存储位置?
答:静态变量编译时存储在静态数据区,程序结束才释放。静态成员也是一样在静态数据区,不占用类空间,所有类实例化的对象共用
在类外有什么办法可以访问类的非公有成员?
答:友元;通过公有成员函数;继承后使用成员函数可以访问父类protected变量。
什么叫抽象类?
答:含纯虚函数的类。不能用来定义对象,但是可以定义指针,子类继承抽象类后作出自己的实现。抽象类指针可以指向很多种 继承抽象类,但实现不同的 子类
运算符重载的意义?
答:为了对用户自定义数据类型的数据的操作与内定义的数据类型的数据的操作形式一致。
不允许重载的5个运算符是哪些?
答:
- .*(成员指针访问运算符号)
- ::域运算符
- Sizeof 长度运算符号
- ?:条件运算符号 (a>0 ? ture : false)
- .(成员访问符)
运算符重载的三种方式?
答:普通函数,友元函数,类成员函数。
流运算符为什么不能通过类的成员函数重载?一般怎么解决?
答:因为通过类的成员函数重载必须是运算符的第一个是自己,而对流运算的重载要求第一个参数是流对象。所以一般通过友元来解决。
赋值运算符和拷贝构造函数的区别与联系?
答:
相同点:创建类对象时,如果没有重载,两者是相同的功能,都是将一个对象copy到另一个中去,调用拷贝构造。
不同点:在不需要创建新对象时,使用赋值,是直接浅拷贝数据。
在哪种情况下要调用该类的析构函数?
答:对象生命周期结束时。
对象间是怎样实现数据的共享的?
答:类的静态成员变量存储在静态数据区,不占用类的存储空间,是所有类成员公有的。
友元关系有什么特性?
答:单向的(A是B友元,B不是A的友元),非传递的(A是B的,B是C的,A不是C的),不能继承的。
对 对象成员进行初始化的次序是什么?
答:成员对象在类中声明的次序来决定的。
类和对象之间的关系是什么?
答:类是对象的抽象,对象是类的实例。
对类的成员的访问属性有什么?
答:public,protected(继承后子类函数可以访问父类protected变量),private。
const char *p和char * const p; 的区别
答:
如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;
如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。
是不是一个父类写了一个virtual 函数,如果子类覆盖它的函数不加virtual ,也能实现多态?
答:
virtual修饰符会被隐形继承的。
virtual可加可不加,子类覆盖它的函数不加virtual ,也能实现多态。
函数重载是什么意思?它与虚函数的概念有什么区别?
答:函数重载是一个同名函数完成不同的功能,编译系统在编译阶段通过函数参数个数、参数类型不同,函数的返回值来区分该调用哪一个函数,即实现的是静态的多态性。但是记住:不能仅仅通过函数返回值不同来实现函数重载。
而虚函数实现的是在基类中通过使用关键字virtual来申明一个函数为虚函数,含义就是该函数的功能可能在将来的派生类中定义或者在基类的基础之上进行扩展,系统只能在运行阶段才能动态决定该调用哪一个函数,所以实现的是动态的多态性。它体现的是一个纵向的概念,也即在基类和派生类间实现。
构造函数和析构函数是否可以被重载,为什么?
答:构造函数可以被重载,析构函数不可以被重载。因为构造函数可以有多个且可以带参数,而析构函数只能有一个,且不能带参数。
如何定义和实现一个类的成员函数为回调函数?
答:
使用函数指针的话,如果类成员函数是静态的,那和普通函数一样,用指针指向此函数,然后就可以用指针调用。如果不是静态的,那么需要this指针确定是哪个类对象调用。实现起来比较复杂,写法奇怪,一般不用。
如果是C++11,可以用function,通过bind将需要的信息绑定形成function后再传递
虚函数是怎么实现的?
答:简单说来使用了虚函数表. 在类中使用一个指针(在对象内存的最前端),指向虚函数表,虚函数表存储了类的虚函数地址.
子类继承父类时可能会继承多个虚函数表,但是子类虚函数表中存放的是 子类重新实现的虚函数 的地址,以此实现多态
抽象类不会产生实例,所以不需要有构造函数。
答: 错,抽象类里面也有成员变量,可能需要初始化,只是存在纯虚函数还没有实现
从一个模板类可以派生新的模板类,也可以派生非模板类。
答:对
main 函数执行以前,还会执行什么代码?
答案:全局对象的构造函数会在main 函数之前执行。
当一个类A 中没有声明任何成员变量与成员函数,这时sizeof(A)的值是多少,如果不是零,请解释一下编译器为什么没有让它为零。(Autodesk)
答案:应该是1,这个字节是占位用的,说明这块内存是有效的,不能被分配走
delete与 delete []区别:
答:delete只会调用一次析构函数(变量析构),而delete[]会调用每一个成员的析构函数(数组中每个成员析构)。
子类析构时要调用父类的析构函数吗?
答:会调用。析构函数调用的次序是 子类析构,成员析构,父类析构 构造时顺序相反
继承的优缺点。
答:
优点:
代码复用;层次结构利于维护;实现多态;
缺点:
紧耦合,父类改动影响许多子类; 继承较死板,把不需要的东西也继承下来了;
解释堆和栈的区别。
答:栈区(stack)--- 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
堆(heap)一般由程序员分配释放, 若程序员不释放,程序结束时由OS回收 。
一个类的构造函数和析构函数什么时候被调用,是否需要手工调用?
答:构造函数在创建类对象的时候被自动调用,析构函数在类对象生命期结束时,由系统自动调用。
什么是预编译/预处理?
答:在编译之前,处理宏定义,头文件包含,条件编译(#ifdef). 主要是做文本替换工作
使用预编译头的好处?
答:使用预编译头是为了加快编译速度。将常用头文件都总结到一个头文件,指定其为预编译头文件。编译器会自动将预编译头文件预先编译成二进制形式,并在实际编译源文件时直接使用预编译头文件,从而加快编译速度。
多态的作用?
答:接口统一,子类的某些实现不同的函数有相同接口;
父类指针指向子类对象,可以复用代码操作;
调用的成员如果有父类实现和子类实现,可以自由选择 (包括函数和变量)
虚函数与普通成员函数的区别?内联函数和构造函数能否为虚函数?
答案:
区别:虚函数有虚指针和虚函数表,虚指针指向虚函数表,表里存储虚函数地址。内联函数和构造函数不能为虚函数。 (注:普通成员函数和一般函数都是存储在公共代码区)
c++内存区 (划分4部分)
全局数据区(静态区):存放全局变量,静态数据,常量(如常量字符串);
代码区:存放所有函数代码,程序的二进制代码。
栈区:存放为运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
堆区:new、malloc、realloc分配的内存块。
析构函数为什么要虚拟?
答案:父类指针指向子类对象时,不同子类可能申请了堆区空间,通过父类虚析构使得可以调用正确的子类析构,防止内存泄露。
C++中类型为private的成员变量可以由哪些函数访问?
答:只可以由本类中的成员函数和友元函数访问
请说出类中private,protect,public三种访问限制类型的区别
答:private是私有类型,只有本类中的成员函数访问; protect是保护型的,本类和子类的成员函数可访问 ; public是公有类型,任何类都可以访问.
类中成员变量怎么进行初始化?
答:可以通过构造函数的初始化列表或构造函数的函数体实现。
在什么时候需要使用"常引用"?
答:不希望进行拷贝,但也不希望被修改 ,一般进行传参时用
引用与指针有什么区别?
答 :
1、指针在使用中可以指向其它对象,但是引用只能是一个对象的引用,不能被改变;
2、指针可以有多级指针(例**p);
3、引用在使用变量名时自动加*,代表指向的变量;指针变量名是指向的地址
描述实时系统的基本特性
答 、要求在规定时间内完成指定任务,不仅要正确还要及时;(可分软实时和硬实时) 软实时允许一定误差,绝大部分情况能及时就可以了,硬实时要求100%及时
堆栈溢出一般是由什么原因导致的?
答 、递归太深;申请的内存一直不释放;指针越界(访问非法内存)
IP地址的编码分为哪俩部分?
答: IP地址由两部分组成,网络号和主机号。ipv4 32位
网络前缀和接口标识 ipv6 128位
不能做switch()的参数类型是:
答 :switch的参数不能为实型(浮点型)。
如何使用一个别的地方定义过的全局变量?
答 :可以用头文件的方式,也可以用extern关键字;
用头文件方式假定你将那个变量写错了,在编译期间会报错,extern是在链接期间报错
c++编译过程?
答 :预处理- 编译- 汇编- 链接 编译: 转成汇编语言文件 汇编: 转换成目标文件,目标文件是二进制文件,通常具有.o或.obj扩展。 链接: 多个目标文件及所需的库文件组合生成最终的可执行文件
对于一个频繁使用的短小函数,在C语言中应该用什么实现,在C++中应该用什么实现?
答 、c用宏定义,c++用inline
C++是不是类型安全的?
答案:不是。两个不同类型的指针之间可以强制转换
简述数组与指针的区别?
答:
数组是一些同类型数据的集合,指针是变量,指向一块内存;数组创建后空间就定下来了,由数组变量名作为指针管理这片内存,不能改变指向了,指针创建后还可以改变指向;数组要么在静态存储区被创建(如全局数组),要么在栈上被创建,指针可以随时指向任意类型的内存块。
C++函数中值的传递方式
答:值传递、指针传递、引用传递(本质也是指针)
内存的分配方式
答:分配方式有三种,
1、 静态存储区,是在程序编译时就已经分配好的,在整个运行期间都存在,如全局变量、常量、静态变量。
2、 栈上分配,函数内的局部变量就是从这分配的,但分配的内存容易有限。
3、 堆上分配,也称动态分配,如我们用new,malloc分配内存,用delete,free来释放的内存。
extern"C"有什么作用?
答:告诉c++编译器,我括起来的东西是c实现的,由于C++和C的函数编译后函数命名格式不同,所以需要告诉编译器是什么格式,以实现C++与C及其它语言的混合编程。
c++支持函数重载,所以命名和C不同
用什么函数开启新进程、线程。
答案:
C++有很多不同平台的接口,从c++11后线程是有语言支持的标准库的,通过thread。进程则还是和平台相关,一般有 fork创建进程,调用 exec执行任务; Boost库创建进程等
SendMessage和PostMessage有什么区别
答案:这两个函数是windows api ,用于进程间通信;SendMessage是阻塞的,等待消息被处理。PostMessage是非阻塞的,马上走到PostMessage的下一行。
CMemoryState主要功能是什么
答案:MFC中用于查看内存使用情况,解决内存泄露问题。
#include <filename.h> 和 #include "filename.h" 有什么区别?
答:对于#include <filename.h> ,编译器从标准库路径开始搜索 filename.h
对于#include "filename.h" ,编译器从用户的工作路径开始搜索 filename.h
处理器标识#error的目的是什么?
答:是一种预处理命令,预处理走到这一行时,输出一条错误信息,并中止构建。
#if!defined(AFX_..._HADE_H)
#define(AFX_..._HADE_H)
......
#endif作用?
答:防止该头文件被重复引用。
在定义一个宏的时候要注意什么?
答:定义部分的每个形参和整个表达式都必须用括号括起来,以避免不可预料的错误发生
数组在做函数实参的时候会转变为什么类型?
答:数组在做实参时会变成指针类型。
系统会自动打开和关闭的3个标准的文件是?
答:
(1) 标准输入----键盘---stdin
(2) 标准输出----显示器---stdout
(3) 标准出错输出----显示器---stderr
cout,cin都是流对象,使用时其实是将字符串写到缓冲区;收到换行符时(或缓冲区满),才会将缓冲区数据一并清空并在显示设备输出。获取输入数据也是从缓冲区拿。
cin、cout、cerr各自绑定了一个标准流
fprintf(stdout, "yes"); 和 printf("yes");相等 cout应该也是类似的
在Win32下 char, int, float, double各占多少位?
答:
(1) Char 占用8位
(2) Int 占用32位
(3) Float 占用32位
(4) Double 占用64位
strcpy()和memcpy()的区别?
答:strcpy()和memcpy()都可以用来拷贝字符串,strcpy()拷贝以'\0'结束,但memcpy()必须指定拷贝的长度。(按字节数拷贝内存)
说明define和const在语法和含义上有什么不同?
答:(1) #define在编译阶段符号就被值替换了,它没有类型;
(2) Const是定义常变量,仍是变量,具有类型,分配内存,可以用sizeof测出长度,但一般不能改。
说出字符常量和字符串常量的区别,并使用运算符sizeof计算有什么不用?
答:字符常量是指单个字符,字符串常量以'\0'结束,使用运算符sizeof计算多占一字节的存储空间。('a' "a")
简述全局变量的优缺点?
答:便于数据共享,但是破坏封装性,可读性也降低,而且使用时容易出现多用户访问导致数据错误,debug困难
外部链接性和内部链接性?
答:
外部链接性指的是变量或函数可以在多个源文件之间共享和访问。具有外部链接性的变量或函数可以在不同的源文件中声明和定义,然后通过外部链接进行连接和使用。
内部链接性指的是变量或函数仅在当前源文件中可见和访问。具有内部链接性的变量或函数只能在同一源文件中使用,无法在其他源文件中访问。
具有外部链接性的变量或函数可以在多个源文件中声明和定义,而具有内部链接性的变量或函数只能在同一源文件中声明和定义。
具有外部链接性的变量在程序运行期间始终存在,而具有内部链接性的变量在程序启动时创建,程序结束时销毁。
总结static的应用和作用?
答:
(1)函数中的static局部变量只被创建一次,下次调用时仍维持上次的值;
(2)在模块内的static全局变量只能在模块内访问; (内部链接性)
(3)在模块内的static函数只可被这一模块内的其它函数调用; (内部链接性)
(4)static成员变量属于整个类所拥有,所有类对象只有一份拷贝;
(5)static成员函数属于整个类所拥有,不接收this指针,因而只能访问static成员变量。
总结const的应用和作用?
答:
(1)创建常量(必须初始化),之后不能修改
(2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;
(3)const可以修饰函数形参,表明参数在函数内部不能改变其值,一般是const的引用;
(4)类的成员函数加const,则表明其是一个常函数,不能修改类的成员变量;
(5)函数返回值加const,使得返回内容不能修改,一般是指针或引用。
什么是指针?谈谈你对指针的理解?
答:指针是一个变量,其存放一个内存地址;
指针变量的类型决定从内容取数据的方式;(取几个字节)
什么是常指针,什么是指向常变量的指针?
答:常指针的含义是该指针所指向的地址不能变,但该地址所指向的内容可以变化。 int* const p;
指向常变量的指针是指该指针的变量本身的地址可以变化,但是它所指的内容不可以被修改。const int *p;
函数指针和指针函数的区别?
答:函数指针是指向一个函数入口的指针;
指针函数是一个返回指针的函数。
简述Debug版本和Release版本的区别?
答:Debug版本是调试版本,带调试信息,且没有进行编译器优化行为;Release版本是发布给用户的版本,不带调试信息,一般由编译器进行优化,运行速度更快,体积更小
指针的几种典型应用情况?
答:
int *p[n];-----指针数组,每个元素均为指向整型数据的指针。
int (*)p[n];---p为指向一维数组的指针,这个一维数组有n个整型数据。对数组名取地址,类型是整个数组
int *p();------返回指针的函数
int (*p)(int,int);----p为指向函数的指针,函数返回值int,参数两个int。
static函数与普通函数有什么区别?
答:static函数只在本源码文件可见,其他文件不可用,多个文件可以出现同名的static函数。普通函数默认是extern属性的,即外部可见
struct(结构) 和 union(联合)的区别?
答:struct里面可以存储多个变量,都分配内存,同时存在; union只看其中最大的成员分配内存,确保可以存下这种变量,同一时间只有一个成员有效。
class 和 struct 的区别?
答:struct 的成员默认是公有的,而类的成员默认是私有的。
简述枚举类型?
答:枚举方便一次定义一组常量,第一个常量默认赋值0,后续逐个加一。这些常量都视为int型常量;使用枚举可以创建变量,使用定义的常量进行赋值,枚举变量相当于一个int变量,但是取值限定在那几种定义
enum A{ MON,TUE,WED=10,THU,FRI,SAT,SUN }; //WED = 10 THU = 11
enum A a = MON; //0
enum A b = TUE; //1
局部变量和全局变量是否可以同名?
答:能。局部会屏蔽全局。要用全局变量,需要使用"::"(域运算符)。
在什么时候使用常引用?
答:既要防止拷贝构造,又要保护传递给函数的数据不在函数中被改变。
类的声明和实现的分开的好处?
答:
- 屏蔽实现,只给出接口,方便使用,无需关注实现
- 一次编译,在所有被include的地方不用重新编译,不然多处使用include,会链接时报函数重定义
auto_ptr弃用原因
答:1.其复制和赋值都会改变资源所有权 (拷贝构造新auto_ptr或赋给别的auto_ptr会导致旧的失效),在STL中使用时有风险 (如vector中存了指针,需要把其中一个指针赋给另一个指针,导致失效,即容器中元素不能正常复制和赋值时会出现意外)
2.不支持对象数组管理 auto_ptr<int[ ]> array(new int[5]); //不能做,其实现的析构不能支持数组对象销毁
什么叫智能指针?
答:无需关注内存释放,c++11中引入三种智能指针,在此之前使用auto_ptr。现在用unique_ptr代替auto_ptr
unique_ptr独占管理的内存资源,其被销毁时自动调用析构释放管理的内存;禁止拷贝构造和赋值运算符;支持move语义。
shared_ptr共享管理的内存资源,可以多个shared_ptr都指向一片内存;允许拷贝构造和赋值运算进行复制;通过引用计数确保没有指针指向内存时再释放这块内存。
weak_ptr解决shared_ptr循环引用的问题,不增加引用计数。如果类A中有一个shared_ptr指针指向类B,B中有一个shared_ptr指针指向类A
在实际中可能会有两个实例的智能指针相互指向的问题,释放时循环依赖。
winsock建立连接的主要实现步骤?
答:
服务器端:socket()建立套接字,绑定(bind)端口并监听(listen)连接,用accept()等待客户端连接, accept()发现有客户端连接,建立一个新的套接字,自身重新开始等待连接。该新产生的套接字使用send()和recv()写读数据,直至数据交换完毕,closesocket()关闭套接字。
客户端:socket()建立套接字,连接(connect)服务器,连接上后使用send()和recv(),在套接字上写读数据,直至数据交换完毕,closesocket()关闭套接字。
套接字关闭时有两个函数,close和shutdown,close使引用计数减1,计数为0释放套接字,未发送的数据仍会继续发;shutdown切断连接,但没有释放socket
套接字三种类型
答:流式socket(tcp传输),数据报式(udp传输),原始socket(可以读写内核没有处理的IP数据包)
C++多态的写法
答:父类使用虚函数,子类继承后重新实现;然后父类指针或引用指向子类对象,调用这个虚函数时实现多态
静态库与动态库区别
答:库是一些成熟的可以复用的代码。本质上来说是一种可执行二进制代码;分为静态库(.a、.lib)与动态库(.so、.dll),其在链接时行为不同。静态库直接编入程序可执行文件,可以独立运行可执行文件;动态库是独立于可执行文件的,可执行文件无法单独运行。
动态库也分为装入时链接和运行时链接,一种是在程序调入内存产生进程时加载,另一个是程序运行到一半需要使用动态库的资源时将其调入。
派生新类的过程要经历三个步骤
答:1.吸收基类成员(除构造函数和析构函数之外的全部成员)
2.改造基类成员 (继承方式改变成员属性 和 同名隐藏)
3.添加新成员
怎样定义一个纯虚函数?含有纯虚函数的类称为什么?
答:在虚函数的后面加=0,含有纯虚函数的类称为抽象类。
简述Visual C++ 、Win32 API和MFC之间的关系?
答:(1) Visual C+是一个以C++程序设计语言为基础的、集成的、可视化的编程环境;
(2) Win32 API是32位Windows操作系以C/C++形式提供的一组应用程序接口;
(3) MFC是对Win32 API的封装,简化了开发过程。
怎样消除多重继承中的二义性?
答: 继承多个父类导致含有多个名字相同的成员,使用此成员时编译器不知道该用哪个
1.作用域限定符,指定我要用哪个父类继承过来的成员 2.子类创建同名对象覆盖所有继承来的同名成员 3. 虚继承,用于菱形继承,中间两个类进行虚继承
继承与虚继承,内存模型
答:普通继承,成员变量先排父类后子类;
如果类中有虚函数,则在内存最开始加一个虚函数表指针,指向虚函数表,里面存放虚函数入口地址;
子类普通继承父类,如果没有重新实现,那虚函数指针和父类一样,指向的虚函数表内容也一样,如果重新实现了,那虚函数表项会改成自己的实现的函数地址;在子类中新增的虚函数排在父类继承过来的虚函数之后(这些从父类继承的虚函数可能在子类有重新实现,也可能没有,但是位置肯定是占住的);
菱形继承时(B、C继承A, D继承B和C)情况就是: A的虚函数表指针,A成员变量,B成员变量, A的虚函数表指针,A成员变量,C成员变量,D成员变量
采用虚继承的菱形继承:当B和C虚继承A时,情况就和上述不同了,首先是B/C的虚基类指针,然后是B/C的成员变量,然后才是A的虚函数表指针,A的成员变量;
D继承B和C, 首先是B的虚基类指针,然后是B的成员变量,C的虚基类指针,C的成员变量,D的成员变量,A的虚函数表指针,A的成员变量
什么叫静态关联,什么叫动态关联
答:在多态中,如果程序在编译阶段就能确定实际执行动作,则称静态关联(用对象调用),
如果等到程序运行才能确定叫动态关联(父类指针指向子类对象调用)。