)小于二点四<含括号的四则运算教案,含括号的四则运算教案里应该填啥

查看: 4828|回复: 6
怎么表示 & 这个符号(尖括号),谢谢!
\langle、\rangle&br&数学环境下使用
非得在数学环境底下用啊
那重新定义一下&br&&br&\newcommand\langlen{\ensuremath{\langle}}
仅仅是想在正文中输出:H&sub&2&/sub&O
\verb$H&sub&2&/sub&O$
成啦!多谢!
Powered by&p&&b&1.在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?&/b&&br&&br&答:首先,extern是C/C++语言中表明函数和全局变量作用范围的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。&br&&br&通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。extern &C&是连接申明(linkage &br&declaration),被extern &br&&C&修饰的变量和函数是按照C语言方式编译和连接的。作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:void&br& foo( int x, int y &br&);该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。&br&&br&所以,可以用一句话概括extern “C”这个声明的真实目的:&u&解决名字匹配问题,实现C++与C的混合编程。&/u&&/p&&p&&b&2.头文件中的ifndef/define/endif有什么作用?&/b&&/p&&p&答:这是C++预编译头文件保护符,保证即使文件被多次包含,头文件也只定义一次。&/p&&p&&b&3. #include&file.h& 与 #include &file.h&的区别?&/b&&br&&br&答:前者是从标准库路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。&/p&&p&&b&4.评价一下C/C++各自的特点&/b&&/p&&p&答:C语言是一种结构化语言,面向过程,基于算法和数据结构,所考虑的是如何通过一个过程或者函数从输入得到输出;&/p&&p&C++是面向对象,基于类、对象和继承,所考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题,通过获取对象的状态信息得到输出或实现过程控制。&/p&&p&&b&5.const 有什么用途?&/b&&/p&&p&答:在C/C++中,(1)可以定义const常量,(2)修饰函数的返回值和形参;&/p&&p&在C++中,还可以修饰函数的定义体,定义类的const成员函数。被const修饰的东西受到强制保护,可以预防意外的变动,提高了程序的健壮性。&/p&&p&&b&6.const和#define有什么区别?&/b&&/p&&p&答:(1)const和#define都可以定义常量,但是const用途更广。&/p&&p&(2)const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。&br&&br&(3) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。&/p&&p&&b&7.关于sizeof小结的。&/b&&/p&&p&答:sizeof计算的是在栈中分配的内存大小。&/p&&p&(1) sizeof不计算static变量占得内存;&/p&&p&(2) 32位系统的指针的大小是4个字节,64位系统的指针是8字节,而不用管指针类型;&/p&&p&(3) char型占1个字节,int占4个字节,short int占2个字节&/p&&p&long int占4个字节,float占4字节,double占8字节,string占4字节&/p&&p&一个空类占1个字节,单一继承的空类占1个字节,虚继承涉及到虚指针所以占4个字节&/p&&p&(4) 数组的长度:&/p&&p&若指定了数组长度,则不看元素个数,总字节数=数组长度*sizeof(元素类型)&/p&&p&若没有指定长度,则按实际元素个数类确定&/p&&p&Ps:若是字符数组,则应考虑末尾的空字符。&/p&&p&(5) 结构体对象的长度&/p&&p&在默认情况下,为方便对结构体内元素的访问和管理,当结构体内元素长度小于处理器位数的时候,便以结构体内最长的数据元素的长度为对齐单位,即为其整数倍。若结构体内元素长度大于处理器位数则以处理器位数为单位对齐。&/p&&p&(6) unsigned影响的只是最高位的意义,数据长度不会改变,所以sizeof(unsigned int)=4&/p&&p&(7) 自定义类型的sizeof取值等于它的类型原型取sizeof&/p&&p&(8) 对函数使用sizeof,在编译阶段会被函数的返回值的类型代替&/p&&p&(9) sizeof后如果是类型名则必须加括号,如果是变量名可以不加括号,这是因为sizeof是运算符&/p&&p&(10) 当使用结构类型或者变量时,sizeof返回实际的大小。当使用静态数组时返回数组的全部大小,sizeof不能返回动态数组或者外部数组的尺寸&/p&&p&&b&8.sizeof与strlen的区别?&/b&&/p&&p&答: (1)sizeof的返回值类型为size_t(unsigned int);&/p&&p&(2)sizeof是运算符,而strlen是函数;&/p&&p&(3)sizeof可以用类型做参数,其参数可以是任意类型的或者是变量、函数,而strlen只能用char*做参数,且必须是以’\0’结尾;&/p&&p&(4)数组作sizeof的参数时不会退化为指针,而传递给strlen是就退化为指针;&/p&&p&(5)sizeo是编译时的常量,而strlen要到运行时才会计算出来,且是字符串中字符的个数而不是内存大小;&/p&&p&&b&9.指针和引用的区别?&/b&&/p&&p&答:指针和引用都提供了间接操作对象的功能。&/p&&p&(1) 指针定义时可以不初始化,而引用在定义时就要初始化,和一个对象绑定,而且一经绑定,只要引用存在,就会一直保持和该对象的绑定;&/p&&p&(2) 赋值行为的差异:指针赋值是将指针重新指向另外一个对象,而引用赋值则是修改对象本身;&/p&&p&(3) 指针之间存在类型转换,而引用分const引用和非const应用,非const引用只能和同类型的对象绑定,const引用可以绑定到不同但相关类型的对象或者右值&/p&&p&&b&10.数组和指针的区别?&/b&&/p&&p&答:(1)数组要么在全局数据区被创建,要么在栈上被创建;指针可以随时指向任意类型的内存块;&/p&&p&(2)修改内容上的差别:&/p&&p&char a[] = “hello”;&br&&br&a[0] = ‘X’;&br&&br&char *p = “world”; // 注意p 指向常量字符串&br&&br&p[0] = ‘X’; // 编译器不能发现该错误,运行时错误&/p&&p&(3)用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p &br&所指的内存容量。C++/C &br&语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。&/p&&p&&b&11.空指针和悬垂指针的区别?&/b&&/p&&p&答:空指针是指被赋值为NULL的指针;delete指向动态分配对象的指针将会产生悬垂指针。&/p&&p&(1) 空指针可以被多次delete,而悬垂指针再次删除时程序会变得非常不稳定;&/p&&p&(2) 使用空指针和悬垂指针都是非法的,而且有可能造成程序崩溃,如果指针是空指针,尽管同样是崩溃,但和悬垂指针相比是一种可预料的崩溃。&/p&&p&&b&12.C++中有malloc/free,为什么还有new/delete?&/b&&/p&&p&答:malloc/free是C/C++标准库函数,new/delete是C++运算符。他们都可以用于动态申请和释放内存。&/p&&p&对于内置类型数据而言,二者没有多大区别。malloc申请内存的时候要制定分配内存的字节数,而且不会做初始化;new申请的时候有默认的初始化,同时可以指定初始化;&/p&&p&对于类类型的对象而言,用malloc/free无法满足要求的。对象在创建的时候要自动执行构造函数,消亡之前要调用析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制之内,不能把执行构造函数和析构函数的任务强加给它,因此,C++还需要new/delete。&/p&&p&&b&13.什么是智能指针?&/b&&/p&&p&答:当类中有指针成员时,一般有两种方式来管理指针成员:一是采用值型的方式管理,每个类对象都保留一份指针指向的对象的拷贝;另一种更优雅的方式是使用智能指针,从而实现指针指向的对象的共享。&/p&&p&  智能指针的一种通用实现技术是使用引用计数。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。&/p&&p&  每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。&/p&&p&&b&14.面向对象技术的基本概念是什么,三个基本特征是什么?&/b&&/p&&p&答:基本概念:类、对象、继承; 基本特征:封装、继承、多态。&/p&&p&封装:将低层次的元素组合起来形成新的、更高实体的技术;&br&&br&继承:广义的继承有三种实现形式:实现继承、可视继承、接口继承。&br&&br&多态:允许将子类类型的指针赋值给父类类型的指针&/p&&p&&b&15.C++空类默认有哪些成员函数?&/b&&/p&&p&答:默认构造函数、析构函数、复制构造函数、赋值函数&/p&&p&&b&16.哪一种成员变量可以在一个类的实例之间共享?&/b&&/p&&p&答:static静态成员变量&/p&&p&&b&17.继承层次中,为什么基类析构函数是虚函数?&/b&&/p&&p&答:编译器总是根据类型来调用类成员函数。但是一个派生类的指针可以安全地转化为一个基类的指针。这样删除一个基类的指针的时候,C++不管这个指针指向一个基类对象还是一个派生类的对象,调用的都是基类的析构函数而不是派生类的。如果你依赖于派生类的析构函数的代码来释放资源,而没有重载析构函数,那么会有资源泄漏。&/p&&p&&b&18.为什么构造函数不能为虚函数?&/b&&/p&&p&答:虚函数采用一种虚调用的方法。需调用是一种可以在只有部分信息的情况下工作的机制。如果创建一个对象,则需要知道对象的准确类型,因此构造函数不能为虚函数。&/p&&p&&b&19.如果虚函数是有效的,那为什么不把所有函数设为虚函数?&/b&&/p&&p&答:不行。首先,虚函数是有代价的,由于每个虚函数的对象都要维护一个虚函数表,因此在使用虚函数的时候都会产生一定的系统开销,这是没有必要的。&/p&&p&&b&20.构造函数可以是内联函数&/b&&/p&&p&&b&21.什么是多态?多态有什么作用?&/b&&/p&&p&答:多态就是将基类类型的指针或者引用指向派生类型的对象。多态通过虚函数机制实现。&/p&&p&多态的作用是接口重用。&/p&&p&&b&22.重载和覆盖有什么区别?&/b&&/p&&p&答:虚函数是基类希望派生类重新定义的函数,派生类重新定义基类虚函数的做法叫做覆盖;&/p&&p&重载就在允许在相同作用域中存在多个同名的函数,这些函数的参数表不同。重载的概念不属于面向对象编程,编译器根据函数不同的形参表对同名函数的名称做修饰,然后这些同名函数就成了不同的函数。&/p&&p&重载的确定是在编译时确定,是静态的;虚函数则是在运行时动态确定。&/p&&p&&b&23.公有继承、受保护继承、私有继承&/b&&/p&&p&答:(1)公有继承时,派生类对象可以访问基类中的公有成员,派生类的成员函数可以访问基类中的公有和受保护成员;&/p&&p&(2)私有继承时,基类的成员只能被直接派生类的成员访问,无法再往下继承;&/p&&p&(3)受保护继承时,基类的成员也只被直接派生类的成员访问,无法再往下继承。&/p&&p&&b&24.公有继承时基类受保护的成员,可以通过派生类对象访问但不能修改。&/b&&/p&&p&&b&25.有哪几种情况只能用构造函数初始化列表而不能用赋值初始化?&/b&&/p&&p&答:const成员,引用成员&/p&&p&&b&26.什么是虚指针?&/b&&/p&&p&答:虚指针或虚函数指针是虚函数的实现细节。带有虚函数的每一个对象都有一个虚指针指向该类的虚函数表。&/p&&p&&b&27.C++如何阻止一个类被实例化?一般在什么时候将构造函数声明为private?&/b&&/p&&p&答:(1)将类定义为抽象基类或者将构造函数声明为private;&/p&&p&(2)不允许类外部创建类对象,只能在类内部创建对象&/p&&p&&b&28.main函数执行之前会执行什么?执行之后还能执行代码吗?&/b&&/p&&p&答:(1)全局对象的构造函数会在main函数之前执行;&/p&&p&(2)可以,可以用_onexit 注册一个函数,它会在main 之后执行;&/p&&p&如果你需要加入一段在main退出后执行的代码,可以使用atexit()函数,注册一个函数。&/p&&p&语法:&/p&&p&#include &stdlib.h&&/p&&p&#include &stdio.h&&/p&&p&int atexit(void (*function&)(void));&/p&&p&void fn1( void ), fn2( void ), fn3( void );&/p&&p&int main( void )&/p&&p&{&/p&&p&atexit(fn1);&/p&&p&atexit( fn2 );&/p&&p&printf( &This is executed first.\n& );&/p&&p&}&/p&&p&void fn1()&/p&&p&{&/p&&p&printf( & This is\n& );&/p&&p&}&/p&&p&void fn2()&/p&&p&{&/p&&p&printf( & executed next.& );&/p&&p&}&/p&&p&结果:&/p&&p&This is executed first.&/p&&p&This is executed next.&/p&&p&&b&29.请描述进程和线程的区别?&/b&&/p&&p&答:(1)进程是程序的一次执行,线程是进程中的执行单元;&/p&&p&(2)进程间是独立的,这表现在内存空间、上下文环境上,线程运行在进程中;&/p&&p&(3)一般来讲,进程无法突破进程边界存取其他进程内的存储空间;而同一进程所产生的线程共享内存空间;&/p&&p&(4)同一进程中的两段代码不能同时执行,除非引入多线程。&/p&&p&&b&30.进程间如何通信?&/b&&/p&&p&答:信号、信号量、消息队列、共享内存&/p&&p&&b&31.在网络编程中涉及并发服务器,使用多进程与多线程的区别?&/b&&/p&&p&答:(1)线程执行开销小,但不利于资源管理和保护;进程则相反,进程可跨越机器迁移。&/p&&p&(2)多进程时每个进程都有自己的内存空间,而多线程间共享内存空间;&/p&&p&(3)线程产生的速度快,线程间通信快、切换快;&/p&&p&(4)线程的资源利用率比较好;&/p&&p&(5)线程使用公共变量或者资源时需要同步机制。&/p&&p&&b&32.说一下TCP 3次握手、4次挥手的全过程。&/b&&/p&&p&&b&33.TCP和UDP有什么区别。&/b&&/p&&p&答:&/p&&p&TCP——传输控制协议,提供的是面向连接、可靠的字节流服务。&/p&&p&当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。&/p&&p&UDP——用户数据报协议,是一个简单的面向数据报的传输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快.&/p&&p&TCP协议和UDP协议的一些特性区别如下:&/p&&p&1.TCP协议在传送数据段的时候要给段标号;UDP 协议不需要。&/p&&p&2.TCP协议可靠;UDP协议不可靠。&/p&&p&3.TCP协议是面向连接;UDP协议采用无连接。&/p&&p&4.TCP协议负载较高,采用虚电路;UDP协议低负载。&/p&&p&5.TCP协议的发送方要确认接受方是否收到数据段(3次握手协议)。&/p&&p&6.TCP协议采用窗口技术和流控制。&/p&&p&&b&34.如何编写套接字?&/b&&/p&&p&&b&35.调用函数时要进行参数压栈,一般情况下顺序是从最右边参数往左压栈。&/b&&/p&&p&&b&36.经常要操作的内存分为那几个类别?&/b&&/p&&p&答:(1)栈区:由编译器自动分配和释放,存放函数的参数值、局部变量的值等;&/p&&p&(2)堆:一般由程序员分配和释放,存放动态分配的变量;&/p&&p&(3)全局区(静态区):全局变量和静态变量存放在这一块,初始化的和未初始化的分开放;&/p&&p&(4)文字常量区:常量字符串就放在这里,程序结束自动释放;&/p&&p&(5)程序代码区:参访函数体的二进制代码。&/p&&p&&b&37.请讲述堆和栈的区别。&/b&&/p&&p&答:(1)申请方式不同。栈上有系统自动分配和释放;堆上有程序员自己申请并指明大小;&/p&&p&(2)栈是向低地址扩展的数据结构,大小很有限;堆是向高地址扩展,是不连续的内存区域,空间相对大且灵活;&/p&&p&(3)栈由系统分配和释放速度快;堆由程序员控制,一般较慢,且容易产生碎片;&/p&&p&&b&38.全局变量放在&u&数据段&/u&,内部变量static int count;放在&u&数据段&/u&,内部变量char *p=“AAA”,p的位置在&u&堆栈&/u&上,指向的空间的位置&u&数据段&/u&,内部变量char&br& *p=new char;p的位置&u&堆&/u&,指向的空间的位置&u&数据段&/u&&/b&&/p&&p&&br&&/p&&p&&b&39.字符数组与字符串的比较:&u&最明显的区别是字符串会在末尾自动添加空字符。&/u&&/b&&/p&&p&&b&40.函数指针相关概念(C++学习笔记)&/b&&/p&&p&&b&41.类使用static成员的优点,如何访问?&/b&&/p&&p&答:优点:&/p&&p&(1)static 成员的名字是在类的作用域中,因此可以避免与其他类的成员或全局对象名字冲突;&/p&&p&(2)可以实施封装。static 成员可以是私有成员,而全局对象不可以;&/p&&p&(3) static 成员是与特定类关联的,可清晰地显示程序员的意图。&/p&&p&static 数据成员必须在类定义体的外部定义(正好一次),static 关键字只能用于类定义体内部的声明中,定义不能标示为static. &br&不像普通数据成员,static成员不是通过类构造函数进行初始化,也不能在类的声明中初始化,而是应该在定义时进行初始化.保证对象正好定义一次的最好办法,就是将static&br& 数据成员的定义放在包含类非内联成员函数定义的文件中。&/p&&p&静态数据成员初始化的格式为:&/p&&p&<数据类型><类名>::<静态数据成员名>=<值>&/p&&p&类的静态数据成员有两种访问形式:&/p&&p&<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>&/p&&p&&b&42. static数据成员和static成员函数&/b&&/p&&p&答:(1)static数据成员:&br&&br&static数据成员独立于该类的任意对象而存在;每个static数据成员是与类关联的对象,并不与该类的对象相关联。Static数据成员(const&br&&br&static数据成员除外)必须在类定义体的外部定义。不像普通数据成员,static成员不是通过类的构造函数进行初始化,而是应该在定义时进行初始化。&br&&br&(2)static成员函数:&br&&br&Static成员函数没有this形参,它可以直接访问所属类的static成员,不能直接使用非static成员。因为static成员不是任何对象的组成部分,所以static成员不能被声明为const。同时,static成员函数也不能被声明为虚函数。&/p&&p&&b&43.static成员变量定义放在cpp文件中,不能放在初始化列表中。Const static成员可就地初始化。&/b&&/p&&p&&br&&/p&&p&&b&44.如何引用一个已经定义过的全局变量?&/b&&/p&&p&答:可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变量,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。&/p&&p&&b&44.static关键字的作用。&/b&&/p&&p&答:static总是使得变量或对象的存储形式变成静态存储,连接方式变成内部连接,对于局部变量(已经是内部连接了),它仅改变其存储方式;对于全局变量(已经是静态存储了),它仅改变其连接类型。&/p&&p&&b&45.奈奎斯特定理&/b&&/p&&p&&b&46.香农定理&/b&&/p&&p&&b&47.多态类中的虚函数表是 Compile-Time,还是 Run-Time时建立的?&/b&&/p&&p&答案:虚拟函数表是在编译期就建立了,各个虚拟函数这时被组织成了一个虚拟函数的入口地址的数组。而对象的隐藏成员--虚拟函数表指针是在运行期--也就是构造函数被调用时进行初始化的,这是实现多态的关键。&/p&&p&&b&48. 一个父类写了一个 virtual 函数,如果子类覆盖它的函数不加 virtual ,也能实现多态?&/b&&/p&&p&&b&在子类的空间里,有没有父类的这个函数,或者父类的私有变量? (华为笔试题)&/b&&/p&&p&答案:只要基类在定义成员函数时已经声明了 virtue关键字,在派生类实现的时候覆盖该函数时,virtue关键字可加可不加,不影响多态的实现。子类的空间里有父类的所有变量(static除外)。&/p&&p&&b&49. 完成字符串拷贝可以使用 sprintf、strcpy 及 memcpy 函数,请问这些函数有什么区别&/b&&/p&&p&&b&,你喜欢使用哪个,为什么?&/b&&/p&&p&答案:这些函数的区别在于 实现功能以及操作对象不同。&/p&&p&(1)strcpy 函数操作的对象是字符串,完成从源字符串到目的字符串的拷贝功能。&/p&&p&(2)sprintf 函数操作的对象不限于字符串:虽然目的对象是字符串,但是源对象可以是字符串、也可以是任意基本类型的数据。这个函数主要用来实现(字符串或基本数据类型)向字符串的转换功能。如果源对象是字符串,并且指定 %s 格式符,也可实现字符串拷贝功能。&/p&&p&(3)memcpy &br&函数顾名思义就是内存拷贝,实现将一个内存块的内容复制到另一个内存块这一功能。内存块由其首地址以及长度确定。程序中出现的实体对象,不论是什么类型,其最终表现就是在内存中占据一席之地(一个内存区间或块)。因此,memcpy&br&&br&的操作对象不局限于某一类数据类型,或者说可适用于任意数据类型,只要能给出对象的起始地址和内存长度信息、并且对象具有可操作性即可。鉴于memcpy&br& 函数等长拷贝的特点以及数据类型代表的物理意义,memcpy &br&函数通常限于同种类型数据或对象之间的拷贝,其中当然也包括字符串拷贝以及基本数据类型的拷贝。&/p&&p&对于字符串拷贝来说,用上述三个函数都可以实现,但是其实现的效率和使用的方便程度不同:&/p&&p&o strcpy 无疑是最合适的选择:效率高且调用方便。&/p&&p&o sprintf 要额外指定格式符并且进行格式转化,麻烦且效率不高。&/p&&p&o memcpy 虽然高效,但是需要额外提供拷贝的内存长度这一参数,易错且使用不便;并且如果长度指定过大的话(最优长度是源字符串长度 + &br&1),还会带来性能的下降。其实 strcpy 函数一般是在内部调用 memcpy 函数或者用汇编直接实现的,以达到高效的目的。因此,使用 &br&memcpy 和 strcpy 拷贝字符串在性能上应该没有什么大的差别。&/p&&p&对于非字符串类型的数据的复制来说,strcpy 和 snprintf 一般就无能为力了,可是对 memcpy &br&却没有什么影响。但是,对于基本数据类型来说,尽管可以用 memcpy &br&进行拷贝,由于有赋值运算符可以方便且高效地进行同种或兼容类型的数据之间的拷贝,所以这种情况下 memcpy 几乎不被使用 。memcpy &br&的长处是用来实现(通常是内部实现居多)对结构或者数组的拷贝,其目的是或者高效,或者使用方便,甚或两者兼有。&/p&&p&&b&50. 应用程序在运行时的内存包括代码区和数据区,其中数据区又包括哪些部分?&/b&&/p&&p&答:对于一个进程的内存空间而言,可以在逻辑上分成 3个部份:代码区,静态数据区和动态数据区。&/p&&p&动态数据区一般就是“堆栈”。 栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”。&/p&&p&全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。程序通过堆栈的基地址和偏移量来访问本地变量。&/p&&p&&b&51. C++函数中值的传递方式有哪几种?&/b&&/p&&p&答:三种传递方式为:值传递、指针传递和引用传递。&/p&&p&&b&52. C++里面是不是所有的动作都是main()引起的?如果不是,请举例.&/b&&/p&&p&比如全局变量的初始化,就不是由main函数引起的&/p&&p&举例: class A{};&/p&&p&A //a的构造函数限执行&/p&&p&int main() {}&/p&&p&&b&53. 下列哪两个是等同的&/b&&/p&&p&&/p&&p&A const int* a = &b;&/p&&p&B const* int a = &b;&/p&&p&C const int* const a = &b;&/p&&p&D int const* const a = &b;&/p&&p&&b&54. 内联函数在编译时是否做参数类型检查?&/b&&/p&&p&答:内联函数要做参数类型检查, 这是内联函数跟宏相比的优势。&/p&&p&&b&55. 全局变量和局部变量有什么区别?实怎么实现的?操作系统和编译器是怎么知道的?&/b&&/p&&p&(1)生命周期不同:&/p&&p&全局变量随主程序创建和创建,随主程序销毁而销毁&/p&&p&局部变量在局部函数内部,甚至局部循环体等内部存在,退出就不存在; 内存中&/p&&p&分配在全局数据区&/p&&p&(2)使用方式不同:通过声明后全局变量程序的各个部分都可以用到;局部变量只能在局部使用,分配在栈区&/p&&p&操作系统和编译器通过内存分配的位置来知道的,全局变量分配在全局数据段并且在程序开始运行的时候被加载。局部变量则分配在堆栈里面 。&/p&&p&&b&56. 有 A 、 B 、 C 、 D 四个人,要在夜里过一座桥。他们通过这座桥分别需要耗时 1 、 2 、 5 、 10 分钟,只有一支手电,并且同时最多只能两个人一起过桥。请问,如何安排,能够在 17 分钟内这四个人都过桥?&/b&&/p&&p&Solution:关键是时间最长的两个人必须同时过桥&/p&&p&The First Time : A(1) 和 B(2) 过桥, A(1) 返回 Cost : 1+2&/p&&p&The Second Time : C(5) 和 D(10) 过桥, B(2) 返回 Cost : 10+2&/p&&p&The Third Time A(1) 和 B(2) 过桥 Cost : 2&/p&&p&Total Time Cost : (1+2)+(10+2)+2=17 minutes&/p&&p&57. &b&static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?&/b&&/p&&p&答:static全局变量与普通全局变量区别:static全局变量只初使化一次,防止在其他文件单元中被引用;&/p&&p&static局部变量和普通局部变量区别:static局部变量只被初始化一次,下一次依据上一次结果值;&/p&&p&static函数与普通函数区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。&/p&&p&&b&58. 程序的局部变量存在于(堆栈)中,全局变量存在于(静态区 )中,动态申请数据存在于( 堆)中。&/b&&/p&&p&&br&&/p&&p&&b&59. 对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?&/b&&/p&&p&c用宏定义,c++用inline&/p&&p&&b&60. 有1,2,....一直到n的无序数组,求排序算法,并且要求时间复杂度为O(n),空间复杂度O(1),使用交换,而且一次只能交换两个数。&/b&&/p&&p&#include&iostream.h&&/p&&p&Using namespace std;&/p&&p&int main(){&/p&&p&int a[] = {10,6,9,5,2,8,4,7,1,3};&/p&&p&int len = sizeof(a) / sizeof(int);&/p&&p&&/p&&p&for(int i = 0; i & )&/p&&p&{&/p&&p&temp = a[a[i] - 1];&/p&&p&a[a[i] - 1] = a[i];&/p&&p&a[i] =&/p&&p&if ( a[i] == i + 1)&/p&&p&i++;&/p&&p&}&/p&&p&for (int j = 0; j & j++)&/p&&p&cout&&a[j]&&&,&;&/p&&p&return 0;&/p&&p&}&/p&
1.在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”? 答:首先,extern是C/C++语言中表明函数和全局变量作用范围的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。 通常,在模块的头文件中对本模块提供给…
&p&此套视频分六大阶段,每一阶段都逐渐加深,此套教程已经整理的非常完善,各位学习者基本上按照此套流程,一阶段,一阶段学习来,肯定会入门,逆袭成为大牛。&/p&&p&&b&第一阶段:&/b&&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-8a4bbdfa0_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&455& data-rawheight=&619& class=&origin_image zh-lightbox-thumb& width=&455& data-original=&https://pic4.zhimg.com/50/v2-8a4bbdfa0_r.jpg&&&/figure&&p&&br&&/p&&p&Java基础视频教程&/p&&p&1、毕向东老师的java入门教程&/p&&p&2、小白的福音java入门教程&/p&&p&3、java快速入门教程&/p&&p&此三个教程异曲同工,内容知识点相差不大,可以只学习其中一个哦!&/p&&p&&br&&/p&&p&&b&第二大阶段:&/b&&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-1bbc6f14d55c4a78ce1c4cf_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&556& data-rawheight=&516& class=&origin_image zh-lightbox-thumb& width=&556& data-original=&https://pic2.zhimg.com/50/v2-1bbc6f14d55c4a78ce1c4cf_r.jpg&&&/figure&&p&Java教程&/p&&p&(1)轻松掌握JavaWeb视频教程&/p&&p&(2)6天玩转mysql视频教程&/p&&p&(3)超全面的JavaWeb视频教程&/p&&p&(4)阶段案例--JavaWeb网上图书商城完整&/p&&p&&b&第三大阶段:&/b&&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-14d1a66ec3f9b62cffb4_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&561& data-rawheight=&534& class=&origin_image zh-lightbox-thumb& width=&561& data-original=&https://pic1.zhimg.com/50/v2-14d1a66ec3f9b62cffb4_r.jpg&&&/figure&&p&Java教程&/p&&p&(1)Hibernate5框架&/p&&p&(2)Struts2框架&/p&&p&(3)Spring框架&/p&&p&
Spring2.5视频教程&/p&&p&&b&第四大阶段:&/b&&/p&&p&&b&知识点:&/b&&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-1aa1faf4bdecb_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&394& data-rawheight=&700& class=&content_image& width=&394&&&/figure&&p&&br&&/p&&p&Java教程&/p&&p&(1)ORACLE经典视频教程&/p&&p&(2)Maven精品教程&/p&&p&&b&第五大阶段:&/b&&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-cb915bd31f5712ecc220ec89dcf0f640_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&560& data-rawheight=&444& class=&origin_image zh-lightbox-thumb& width=&560& data-original=&https://pic2.zhimg.com/50/v2-cb915bd31f5712ecc220ec89dcf0f640_r.jpg&&&/figure&&p&Java教程推荐:&/p&&p&(1) Springmvc由浅入深全套视频教程&/p&&p&(2)Mybatis由浅入深全套视频教程&/p&&p&&br&&/p&&p&&b&第六大阶段:&/b&&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-6bfe45c416ca1de7237221_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&517& data-rawheight=&379& class=&origin_image zh-lightbox-thumb& width=&517& data-original=&https://pic4.zhimg.com/50/v2-6bfe45c416ca1de7237221_r.jpg&&&/figure&&p&Java教程推荐:&/p&&p&(1)Java学科巴巴运动网视频教程106集&/p&&p&(2)巴巴运动网续集视频教程&/p&&p&以上就是Java学习路线图的内容,具体配套视频有需要的小伙伴可以私信我,码字不易,有用请点赞分享一下吧!&/p&
此套视频分六大阶段,每一阶段都逐渐加深,此套教程已经整理的非常完善,各位学习者基本上按照此套流程,一阶段,一阶段学习来,肯定会入门,逆袭成为大牛。第一阶段: Java基础视频教程1、毕向东老师的java入门教程2、小白的福音java入门教程3、java快速入…
&p&作者:&a href=&https://link.zhihu.com/?target=https%3A//www.nowcoder.com/profile/1561797& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Re_born&/a&&/p&&p&来源:牛客网&/p&&p&&br&&/p&&p&&b&其实我面试的时候C++基本很少问及,不过还是要有扎实的基础。以下是自己的一份总结,比较适合自己,所以根据你们自己的需求拿走我的笔记,如有错误也请提出我好更改。回馈牛客网,谢谢。&/b&&/p&&p&&br&&/p&&p&&b&1.深拷贝和浅拷贝&/b&&/p&&p&深拷贝(Memberwise copy semantics)是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。&/p&&p&浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。&/p&&p&浅拷贝在类里面有指针成员的情况下只会复制指针的地址,会导致两个成员指针指向同一块内存,这样在要是分别delete释放时就会出现问题,因此需要用深拷贝。&/p&&p&&br&&/p&&p&&b&2.delete this&/b&&/p&&p&在类的成员函数中能不能调用delete this?答案是肯定的,能调用,而且很多老一点的库都有这种代码。假设这个成员函数名字叫release,而delete this就在这个release方法中被调用,那么这个对象在调用release方法后,还能进行其他操作,如调用该对象的其他方法么?答案仍然是肯定 的,调用release之后还能调用其他的方法,但是有个前提:被调用的方法不涉及这个对象的数据成员和虚函数。说到这里,相信大家都能明白为什么会这样了。&/p&&p&&br&&/p&&p&根本原因在于delete操作符的功能和类对象的内存模型。当一个类对象声明时,系统会为其分配内存空间。在类对象的内存空间中,只有数据成员和虚函数表指针,并不包含代码内容,类的成员函数单独放在代码段中。在调用成员函数时,隐含传递一个this指针,让成员函数知道当前是哪个对象在调用它。当调用delete this时,类对象的内存空间被释放。在delete this之后进行的其他任何函数调用,只要不涉及到this指针的内容,都能够正常运行。一旦涉及到this指针,如操作数据成员,调用虚函数等,就会出现不可预期的问题。&/p&&p&为什么是不可预期的问题?delete this之后不是释放了类对象的内存空间了么,那么这段内存应该已经还给系统,不再属于这个进程。照这个逻辑来看,应该发生指针错误,无访问权限之类的令系统崩溃的问题才对啊?这个问题牵涉到操作系统的内存管理策略。delete this释放了类对象的内存空间,但是内存空间却并不是马上被回收到系统中,可能是缓冲或者其他什么原因,导致这段内存空间暂时并没有被系统收回。此时这段内存是可以访问的,你可以加上100,加上200,但是其中的值却是不确定的。当你获取数据成员,可能得到的是一串很长的未初始化的随机数;访问虚函数表,指针无效的可能性非常高,造成系统崩溃。&/p&&p&&br&&/p&&p&大致明白在成员函数中调用delete this会发生什么之后,再来看看另一个问题,如果在类的析构函数中调用delete this,会发生什么?实验告诉我们,会导致堆栈溢出。原因很简单,delete的本质是“为将被释放的内存调用一个或多个析构函数,然后,释放内存”(来自effective c++)。显然,delete this会去调用本对象的析构函数,而析构函数中又调用delete this,形成无限递归,造成堆栈溢出,系统崩溃。&/p&&p&&br&&/p&&p&&b&3.构造函数初始化时必须采用初始化列表一共有三种情况&/b&&/p&&p&1.需要初始化的数据成员是对象(继承时调用基类构造函数)&br&2.需要初始化const修饰的类成员&br&3.需要初始化引用成员数据&/p&&p&&br&&/p&&p&&b&C/C++&/b& &b&内存管理&/b&&/p&&p&&u&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/bizhu12/article/details/6668834& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&blog.csdn.net/bizhu12/a&/span&&span class=&invisible&&rticle/details/6668834&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/p&&p&&u&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/wdzxl198/article/details/9050587& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&blog.csdn.net/wdzxl198/&/span&&span class=&invisible&&article/details/9050587&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/p&&p&&br&&/p&&p&&b&4.C/C++&/b& &b&分配内存&/b&&/p&&p&1) malloc函数:void *malloc(unsigned int size)&/p&&p&在内存的动态分配区域中分配一个长度为size的连续空间,如果分配成功,则返回所分配内存空间的首地址,否则返回NULL,申请的内存不会进行初始化。&/p&&p&2)calloc函数:void *calloc(unsigned int num, unsigned int size)&/p&&p&按照所给的数据个数和数据类型所占字节数,分配一个num * size连续的空间。&/p&&p&calloc申请内存空间后,会自动初始化内存空间为0,但是malloc不会进行初始化,其内存空间存储的是一些随机数据。 &br&3)realloc函数:void *realloc(void *ptr, unsigned int size)&/p&&p&动态分配一个长度为size的内存空间,并把内存空间的首地址赋值给ptr,把ptr内存空间调整为size。&/p&&p&申请的内存空间不会进行初始化。&br&4)new是动态分配内存的运算符,自动计算需要分配的空间,在分配类类型的内存空间时,同时调用类的构造函数,对内存空间进行初始化,即完成类的初始化工作。动态分配内置类型是否自动初始化取决于变量定义的位置,在函数体外定义的变量都初始化为0,在函数体内定义的内置类型变量都不进行初始化。&/p&&p&&u&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/hackbuteer1/article/details/6789164& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&blog.csdn.net/hackbutee&/span&&span class=&invisible&&r1/article/details/6789164&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/p&&p&&br&&/p&&p&&b&处理New分配内存失败情况?&/b&&/p&&p&我们经常会使用new给一个对象分配内存空间,而当内存不够会出现内存不足的情况。C++提供了两种报告方式:&/p&&p&1、抛出bad_alloc异常来报告分配失败;&/p&&p&2、返回空指针,而不会抛出异常&/p&&p&当operator new 无法满足内存需求时,它会不只一次地调用new_handler函数(如果new_handler没有退出程序的话);它会不断地调用,直到找到足够的内存为止。可以用set_new_hander 函数为 new 设置用户自己定义的异常处理函数,也可以让 malloc 享用与 new 相同的异常处理函数。&/p&&p&&br&&/p&&p&&b&当一个类A中没有声命任何成员变量与成员函数这时sizeof(A)的值是多少,如果不是零,请解释一下编译器为什么没有让它为零&/b&&/p&&p&通常是1,用作占位的。&b&为了确保不同对象有不同的地址&/b&&/p&&p&&b&new和malloc的10点区别&/b&&/p&&p&&b&特征&/b&&/p&&p&&b&new/delete&/b&&/p&&p&&b&malloc/free&/b&&/p&&p&分配内存的位置&/p&&p&自由存储区&/p&&p&自由存储区不仅可以是堆,还可以是静态存储区&/p&&p&堆&/p&&p&内存分配成功的返回值&/p&&p&完整类型指针&/p&&p&类型严格与对象匹配,无须进行类型转换,故new是符合&b&类型安全&/b&性的操作符&/p&&p&void*&/p&&p&需要通过强制类型转换将void*指针转换成我们需要的类型&/p&&p&内存分配失败的返回值&/p&&p&默认抛出异常&/p&&p&返回NULL&/p&&p&分配内存的大小&/p&&p&由编译器根据类型计算得出&/p&&p&必须显式指定字节数&/p&&p&处理数组&/p&&p&有处理数组的new版本new[]&/p&&p&需要用户计算数组的大小后进行内存分配&/p&&p&已分配内存的扩充&/p&&p&无法直观地处理&/p&&p&使用realloc简单完成&/p&&p&是否相互调用&/p&&p&可以,看具体的operator new/delete实现&/p&&p&不可调用new&/p&&p&分配内存时内存不足&/p&&p&客户能够指定处理函数或重新制定分配器&/p&&p&无法通过用户代码进行处理&/p&&p&函数重载&/p&&p&允许&/p&&p&不允许&/p&&p&构造函数与析构函数&/p&&p&调用&/p&&p&不调用&/p&&p&&u&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/QG-whz/p/5140930.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&cnblogs.com/QG-whz/p/51&/span&&span class=&invisible&&40930.html&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/p&&p&&br&&/p&&p&&b&5.c++如何避免内存泄漏&/b&&/p&&p&a、使用RAII(ResourceAcquisition Is Initialization,资源获取即初始化)技法,以构造函数获取资源(内存),析构函数释放。&/p&&p&b、相比于使用原生指针,更建议使用&b&&a href=&https://link.zhihu.com/?target=http%3A//lib.csdn.net/base/aiplanning& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&智能&/a&&/b&指针,尤其是&b&&a href=&https://link.zhihu.com/?target=http%3A//lib.csdn.net/base/cplusplus& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&C++&/a&&/b&11标准化后的智能指针。&/p&&p&c、注意delete和delete[]的使用方法。&/p&&p&d、这是很复杂的一种情况,是关于类的copy constructor的。首先先介绍一些概念。&/p&&p&同defaultconstructor一样,标准保证,如果类作者没有为class声明一个copy constructor,那么编译器会在需要的时候产生出来(这也是一个常考点:问道&如果类作者未定义出default/copy constructor,编译器会自动产生一个吗?&答案是否定的)&/p&&p&不过请注意!!这里编译器即使产生出来,也是为满足它的需求,而非类作者的需求!!&/p&&p&而什么时候是编译器&需要&的时候呢?是在当这个class【不表现出】bitwise copy semantics(位逐次拷贝,即浅拷贝)的时候。&/p&&p&在4中情况下class【不表现出】bitwisecopy semantics&/p&&p&(1)、当class内含一个memberobject且该member object声明了一个copy
constructor(无论该copy ctor是类作者自己生明的还是编译器合成的);&/p&&p&(2)、当class继承自一个baseclass且该base class有一个copy constructor(无论
该copy ctor是类作者自己生明的还是编译器合成的);&/p&&p&(3)、当class声明了virtual function;&/p&&p&(4)、当class派生自一个继承链,且该链中存在virtual base class时。&/p&&p&言归正传,如果class中仅仅是一些普通资源,那么bitwisecopy semantics是完全够用的;然而,挡在该class中存在了一块动态分配的内存,并且在之后执行了bitwise copy semantics后,将会有一个按位拷贝的对象和原来class中的某个成员指向同一块heap空间,当执行它们的析构函数后,该内存将被释放两次,这是未定义的行为。因此,在必要的时候需要使用Memberwise copy semantics(即深拷贝),来避免内存泄露。&b&位拷贝拷贝的是地址,而值拷贝则拷贝的是内容。&/b&&/p&&p&6.&b&四种情况下编译器会生成默认构造函数&/b&&/p&&p&其实默认构造函数也是分为两类的:有用的、无用的。&/p&&p&所谓&b&有用的标准也是就默认构造函数会为我们的类做一些初始化操作&/b&。那么无用的就不会做任何工作,从而对我们的类也就没有任何意义。所以,我们通常所说的默认构造函数是指&b&有用的默认构造函数,其英文名字叫nontrivial default constructor&/b&。&/p&&p&那么到底什么时候编译器会为我们产生nontrivial default constructor呢?有下面四中情况:&/p&&p&①如果一个类里面某个成员对象有nontrivial default constructor,编译器就会为我们的类产生nontrivial default constructor。&/p&&p&那么编译器这样做的理由是什么?&/p&&p&答案是因为类成员对象有nontrivial default constructor,那么编译器就需要&b&显式的来调用这个类成员对象的&/b&nontrivial default constructor。而编译器想显式的调用类成员对象的nontrivial default constructor,就需要自己来合成一些代码来调用。但是记住,编译器合成的nontrivial default constructor&b&仅仅调用类成员对象的默认构造函数,而不对我们类里面的其它变量做任何初始化操作。&/b&&/p&&p&也就是说,如果你想初始化类成员变量以外的变量例如一个int、一个String,那么必须&b&自己定义&/b&默认构造函数来完成这些变量的初始化。而编译器会对你定义的默认构造函数做相应的扩展,从而调用类成员对象的nontrivial default constructor。&/p&&p&②如果一个派生类的&b&基类有&/b&nontrivial default constructor,那么编译器会为派生类合成一个nontrivial default constructor。&/p&&p&编译器这样的理由是:因为派生类被合成时需要显式调用基类的默认构造函数。&/p&&p&③如何一个类里面隐式的含有&b&任何virtual function table(或vtbl)、pointer member(或vptr)。&/b&&/p&&p&编译器这样做的理由很简单:因为这些vtbl或vptr需要编译器隐式(implicit)的合成出来,那么编译器就把合成动作放到了默认构造函数里面。所以编译器必须自己产生一个默认构造函数来完成这些操作。&/p&&p&所以如果你的类里带有任何&b&virtual function,那么编译器会合成一个默认构造函数。&/b&&/p&&p&④如果一个&b&类虚继承于其它类。&/b&&/p&&p&编译器这样做的理由和③类似:因为虚继承需要维护一个类似指针一样,可以动态的决定内存地址的东西(不同编译器对虚继承的实现不仅相同)。&/p&&p&那么&b&除了以上四种情况,编译器并不会为我们的类产生默认构造函数。&/b&&/p&&p&&br&&/p&&p&&b&7.c++的const函数特点&/b&&/p&&p&1.不能在const函数中修改所在类的对象的数据,因为const函数中的*this是常量,同样只能访问const函数;&/p&&p&2.const函数中只能调用其他的const函数,不能调用非const函数,因为对象调用函数是需要传递对象自己,const函数中的*this是常量,非const函数中的*this是变量,因此不可以调用(除非去除*this的const属性);&/p&&p&Note:使用const_cast后,可以在const函数中调用非const函数的&/p&&p&3.const对象只能调用const函数 ,但是非const对象可以调用const函数;&/p&&p&4.const函数与同名的非const函数是重载函数。&/p&&p&&br&&/p&&p&8.&b&面向对象的三个基本特征&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/chenyi8888/article/details/5336912& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&blog.csdn.net/chenyi888&/span&&span class=&invisible&&8/article/details/5336912&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&C++继承体系中,初始化时构造函数的调用顺序如下&/p&&p&(1)任何虚拟基类的构造函数按照他们被继承的顺序构造&/p&&p&(2)任何非虚拟基类的构造函数按照他们被继承的顺序构造&/p&&p&(3)任何成员对象的函数按照他们声明的顺序构造&/p&&p&(4)类自己的构造函数&/p&&p&&br&&/p&&p&9.&b&指针和引用&/b&&/p&&p&1、本质:指针是一个变量,存储内容是一个地址,指向内存的一个存储单元。而引用是原变量的一个别名,实质上和原变量是一个东西,是某块内存的别名。&/p&&p&2、指针的值可以为空,且非const指针可以被重新赋值以指向另一个不同的对象。而引用的值不能为空,并且引用在定义的时候必须初始化,一旦初始化,就和原变量“绑定”,不能更改这个绑定关系。(没有NULL的引用可能会比指针效率更高,因为不用测试有效性)&/p&&p&3、对指针执行sizeof()操作得到的是指针本身的大小(32位系统为4,64位系统为8)。而对引用执行sizeof()操作得到的是所绑定的对象的所占内存大小。&/p&&p&4、指针的自增(++)运算表示对地址的自增,自增大小要看所指向单元的类型。而引用的自增(++)运算表示对值的自增。&/p&&p&5、在作为函数参数进行传递时的区别:指针所以函数传输作为传递时,函数内部的指针形参是指针实参的一个副本,改变指针形参并不能改变指针实参的值,通过解引用*运算符来更改指针所指向的内存单元里的数据。而引用在作为函数参数进行传递时,实质上传递的是实参本身,即传递进来的不是实参的一个拷贝,因此对形参的修改其实是对实参的修改,所以在用引用进行参数传递时,不仅节约时间,而且可以节约空间。&/p&&p&&br&&/p&&p&&b&11.构造函数和析构函数能否重载&/b&&/p&&p&函数重载就是同一函数名的不同实现,并且能在编译时能与一具体形式匹配,这样参数列表必须不一样。由于重载函数与普通函数的差别是没有返回值,而返回值不能确定函数重载,所以构造函数可以重载;析构函数的特点是参数列表为空,并且无返回值,从而不能重载。&/p&&p&&br&&/p&&p&11.&b&析构函数什么情况下定义为虚函数&/b&&/p&&p&一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,造成内存泄漏。&/p&&p&如果不需要基类对派生类及对象进行操作,则不能定义虚函数,因为这样会增加内存开销。当类里面有定义虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样会增加类的存储空间。所以只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。&/p&&p&如果基类析构函数不为虚的话,在释放派生类对象的时候就不会调用派生类的析构函数,有可能造成内存泄露。&/p&&p&&br&&/p&&p&12.&b&拷贝构造函数的参数类型必须是引用&/b&&/p&&p&如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构造函数。因此拷贝构造函数的参数必须是一个引用。&br&需要澄清的是,传指针其实也是传值,如果上面的拷贝构造函数写成CClass(const CClass* c_class),也是不行的。事实上,只有传引用不是传值外,其他所有的传递方式都是传值。&/p&&p&&br&&/p&&p&&b&为什么内联函数,构造函数,静态成员函数不能为virtual函数?&/b&&/p&&p&1& 内联函数&/p&&p&内联函数是在编译时期展开,而虚函数的特性是运行时才动态联编,所以两者矛盾,不能定义内联函数为虚函数。&/p&&p&2& 构造函数&/p&&p&构造函数用来创建一个新的对象,而虚函数的运行是建立在对象的基础上,在构造函数执行时,对象尚未形成,所以不能将构造函数定义为虚函数&/p&&p&3& 静态成员函数&/p&&p&静态成员函数属于一个类而非某一对象,没有this指针,它无法进行对象的判别。&/p&&p&4&
友元函数&/p&&p&C++不支持友元函数的继承,对于没有继承性的函数没有虚函数&/p&&p&这个可以从两个角度去理解:&/p&&p&1。virtual意味着在执行时期进行绑定,所以在编译时刻需确定信息的不能为virtual&/p&&p&构造函数需在编译时刻,因为需构造出个对象,才能执行动作。&br&静态成员函数不属于任何一个对象,编译时刻确定不存在执行的时候选择执行哪个的情形。&br&内联函数,由于属于编译器的建议机制,所以其实可以virtual。&/p&&p&2。virtual意味着派生类可以改写其动作&br&派生类的构造函数会先执行基类的构造函数而不是取代基类构造函数,也就是说基类的构造函数可以看作派生类构造函数的组成,所以并不能改写这个函数。&br&静态成员函数不属于任何一个对象,所以更不能改写其动作了。&/p&&p&inline和virtual不会同时起作用。带virtual的函数在不需要动态绑定调用的时候,就可以inline。&/p&&p&&br&&/p&&p&&b&构造函数和析构函数为什么没有返回值?&/b&&/p&&p&构造函数和析构函数是两个非常特殊的函数:它们没有返回值。这与返回值为void的函数显然不同,后者虽然也不返回任何值,但还可以让它做点别的事情,而构造函数和析构函数则不允许。在程序中创建和消除一个对象的行为非常特殊,就像出生和死亡,而且总是由编译器来调用这些函数以确保它们被执行。如果它们有返回值,要么编译器必须知道如何处理返回值,要么就只能由客户程序员自己来显式的调用构造函数与析构函数,这样一来,安全性就被人破坏了。另外,析构函数不带任何参数,因为析构不需任何选项。&/p&&p&&br&&/p&&p&&b&C++异常机制&/b&&/p&&p&异常事件在C++中表示为&b&异常对象&/b&。异常事件发生时,程序使用throw关键字抛出异常表达式,抛出点称为异常出现点,由操作系统为程序设置当前异常对象,然后执行程序的当前异常处理代码块,在包含了异常出现点的最内层的&b&try&/b&块,依次匹配catch语句中的异常对象(只进行类型匹配,catch参数有时在catch语句中并不会使用到)。若匹配成功,则执行catch块内的异常处理语句,然后接着执行&b&try...catch...&/b&块之后的代码。如果在当前的try...catch...块内找不到&b&匹配&/b&该异常对象的catch语句,则由更外层的try...catch...块来处理该异常;如果当前函数内所有的try...catch...块都不能匹配该异常,则递归回退到调用栈的上一层去处理该异常。如果一直退到主函数main()都不能处理该异常,则调用系统函数terminate()终止程序。&/p&&p&&u&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/QG-whz/p/5136883.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&cnblogs.com/QG-whz/p/51&/span&&span class=&invisible&&36883.html&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/p&&p&&br&&/p&&p&&b&析构函数可以抛出异常吗?为什么不能抛出异常?除了资源泄露,还有其他需考虑的因素吗?&/b&&/p&&p&(1)C++中析构函数的执行不应该抛出异常;&/p&&p&(2)如果析构函数抛出异常,则&b&异常点之后的程序不会执行&/b&,如果析构函数在异常点之后执行了某些必要的动作比如释放某些资源,则这些动作不会执行,会造成诸如资源泄漏的问题。&/p&&p&(3)通常异常发生时,c++的机制会调用已经构造对象的析构函数来释放资源,此时若析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成程序崩溃的问题。析构函数中抛出异常导致程序不明原因的崩溃是许多系统的致命内伤&/p&&p&&b&解决办法:&/b&那就是&b&把异常完全封装在析构函数内部,决不让异常抛出函数之外。如使用&/b&&/p&&p&&b&Try&/b&&/p&&p&&b&{
}&/b&&/p&&p&&b&Catch&/b&&/p&&p&&b&{&/b&/这里可以什么都不做,只是&b&保证catch块的程序抛出的异常不会被扔出析构函数之外&/b&。&b&}&/b&&/p&&p&&br&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/fly1988happy/archive//2442765.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&cnblogs.com/fly1988happ&/span&&span class=&invisible&&y/archive//2442765.html&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&br&&/p&&p&&br&&/p&&p&&b&在构造函数和析构函数中抛出异常会发生什么?什么是栈展开?&/b&&/p&&p&&br&&/p&&p&构造函数中可以抛出异常,&b&构造抛异常之前必须把已经申请的资源释放掉&/b&。&b&这样,就算你的对象是new出来的,也不会造成内存泄漏。&/b&&br&因为析构函数不会被调用,所以抛出异常后,你没机会释放资源。&/p&&p&构造函数中抛出异常时概括性总结&br&(1) C++中通知对象构造失败的唯一方法那就是在构造函数中抛出异常;&/p&&p&(2)
构造函数中抛出异常将导致对象的析构函数不被执行;&/p&&p&(3) 当对象发生部分构造时,已经构造完毕的子对象将会逆序地被析构;&/p&&p&&br&&/p&&p&栈展开:抛出异常时,将暂停当前函数的执行,开始查找匹配的catch子句。首先检查throw本身是否在try块内部,如果是,检查与该try相关的catch子句,看是否可以处理该异常。如果不能处理,就退出当前函数,并且释放当前函数的内存并销毁局部对象,继续到上层的调用函数中查找,直到找到一个可以处理该异常的catch。这个过程称为栈展开(stack unwinding)&/p&&p&&br&&/p&&p&&b&C++保护和私有构造函数与析构函数&/b&&/p&&p&&b&如何定义一个只能在堆上(栈上)生成对象的类?&/b&&/p&&p&构造函数定义为protected后,就意味着你不能在类的外部构造对象了,而只能在外部构造该类的子类的对象&/p&&p&构造函数定义为private后,意味着不仅仅不能在类的外部构造对象了,而且也不能在外部构造该类的子类的对象了,只能通过类的static静态函数来访问类的内部定义的对象,单件singleton模式就是私有构造函数的典型实例&/p&&p&对于堆中的对象,通常都是用new/delete来创建/销毁,当调用new时,它会自动调用相应类的构造函数,当调用delete时,它会自动调用相应类的析构函数。而在栈中产生对象时,对象的创建/销毁是自动完成的,也就是在创建时自动调用构造函数,在销毁时自动调用析构函数,即不需要显示调用new/delete,但有个前提是类的构造/析构函数都必须是public的。&br&析构函数无论是protected还是priavte,其共同作用都是禁止在栈中产生对象,因为无法自动完成析构函数的调用,自然就不能在栈中创建对象了;当然如果在堆上创建对象时,也不能直接delete对象了,因为这样也会在外部析构该对象,但是可以间接完成堆对象的析构&/p&&p&私有和保护析构函数区别在于私有的析构函数不仅禁止了栈中产生对象,而且同时也禁止了继承&/p&&p&来源:牛客网&/p&&p&在C++中,类的对象建立分为两种,一种是静态建立,如A a;另一种是动态建立,如A* ptr=new A;这两种方式是有区别的。&/p&&p&静态建立一个类对象,是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象。使用这种方法,直接调用类的构造函数。&/p&&p&动态建立类对象,是使用new运算符将对象建立在堆空间中。这个过程分为两步,第一步是执行operator new()函数,在堆空间中搜索合适的内存并进行分配;第二步是调用构造函数构造对象,初始化这片内存空间。这种方法,间接调用类的构造函数。&/p&&p&那么如何限制类对象只能在堆或者栈上建立呢?下面分别进行讨论。&/p&&p&&br&&/p&&p&1、只能建立在堆上&/p&&p&类对象只能建立在堆上,就是不能静态建立类对象,即不能直接调用类的构造函数。&/p&&p&容易想到将构造函数设为私有。在构造函数私有之后,无法在类外部调用构造函数来构造类对象,只能使用new运算符来建立对象。然而,前面已经说过,new运算符的执行过程分为两步,C++提供new运算符的重载,其实是只允许重载operator new()函数,而operator()函数用于分配内存,无法提供构造功能。因此,这种方法不可以。&/p&&p&当对象建立在栈上面时,是由编译器分配内存空间的,调用构造函数来构造栈对象。当对象使用完后,编译器会调用析构函数来释放栈对象所占的空间。编译器管理了对象的整个生命周期。如果编译器无法调用类的析构函数,情况会是怎样的呢?比如,类的析构函数是私有的,编译器无法调用析构函数来释放内存。所以,编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。&/p&&p&因此,将析构函数设为私有,类对象就无法建立在栈上了。代码如下:&/p&&p&1. &b&class&/b& A&/p&&p&2. {&/p&&p&3. &b&public&/b& :&/p&&p&4.
A(){}&/p&&p&5. &b&void&/b& destory(){ &b&delete&/b& &b&this&/b& ;}&/p&&p&6. &b&private&/b& :&/p&&p&7.
~A(){}&/p&&p&8. };&/p&&p&试着使用A来建立对象,编译报错,提示析构函数无法访问。这样就只能使用new操作符来建立对象,构造函数是公有的,可以直接调用。类中必须提供一个destory函数,来进行内存空间的释放。类对象使用完成后,必须调用destory函数。&/p&&p&上述方法的一个缺点就是,无法解决继承问题。如果A作为其它类的基类,则析构函数通常要设为virtual,然后在子类重写,以实现多态。因此析构函数不能设为private。还好C++提供了第三种访问控制,protected。将析构函数设为protected可以有效解决这个问题,类外无法访问protected成员,子类则可以访问。&/p&&p&另一个问题是,类的使用很不方便,使用new建立对象,却使用destory函数释放对象,而不是使用delete。(使用delete会报错,因为delete对象的指针,会调用对象的析构函数,而析构函数类外不可访问)这种使用方式比较怪异。为了统一,可以将构造函数设为protected,然后提供一个public的static函数来完成构造,这样不使用new,而是使用一个函数来构造,使用一个函数来析构。代码如下,类似于单例模式:&/p&&p&1. &b&class&/b& A&/p&&p&2. {&/p&&p&3. &b&protected&/b& :&/p&&p&4.
A(){}&/p&&p&5.
~A(){}&/p&&p&6. &b&public&/b& :&/p&&p&7. &b&static&/b& A* create()&/p&&p&8.
{&/p&&p&9. &b&return&/b& &b&new&/b& A();&/p&&p&10.
}&/p&&p&11. &b&void&/b& destory()&/p&&p&12.
{&/p&&p&13. &b&delete&/b& &b&this&/b& ;&/p&&p&14.
}&/p&&p&15. };&/p&&p&这样,调用create()函数在堆上创建类A对象,调用destory()函数释放内存。&/p&&p&&br&&/p&&p&2、只能建立在栈上&/p&&p&只有使用new运算符,对象才会建立在堆上,因此,只要禁用new运算符就可以实现类对象只能建立在栈上。将operator new()设为私有即可。代码如下:&/p&&p&1. &b&class&/b& A&/p&&p&2. {&/p&&p&3. &b&private&/b& :&/p&&p&4. &b&void&/b& * operator &b&new&/b& ( &b&size_t&/b& t){}
// 注意函数的第一个参数和返回值都是固定的&/p&&p&5. &b&void&/b& operator &b&delete&/b& ( &b&void&/b& * ptr){}
// 重载了new就需要重载delete&/p&&p&6. &b&public&/b& :&/p&&p&7.
A(){}&/p&&p&8.
~A(){}&/p&&p&9. };&/p&&p&&br&&/p&&p&&b&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/gao/article/details/7397373& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&内联函数和宏定义的区别&/a&&/b&&/p&&p&内联函数用来降低程序的运行时间。当内联函数收到编译器的指示时,即可发生内联:编译器将使用函数的定义体来替代函数调用语句,这种替代行为发生在编译阶段而非程序运行阶段。内联函数仅仅是对编译器的内联建议,编译器是否觉得采取你的建议取决于函数是否符合内联的有利条件。如何函数体非常大,那么编译器将忽略函数的内联声明,而将内联函数作为普通函数处理。&/p&&p&&br&&/p&&p&优点:&/p&&p&1.它通过避免函数调用所带来的开销来提高你程序的运行速度。&/p&&p&2.当函数调用发生时,它节省了变量弹栈、压栈的开销。&/p&&p&3.它避免了一个函数执行完返回原现场的开销。&/p&&p&4.通过将函数声明为内联,你可以把函数定义放在头文件内。&/p&&p&缺点:&/p&&p&1.内联是以代码膨胀(复制)为代价,内联函数增大了可执行程序的体积,导致内存消耗代价较高。&/p&&p&2.C++内联函数的展开是中编译阶段,这就意味着如果你的内联函数发生了改动,那么就需要重新编译代码。&/p&&p&&br&&/p&&p&1.内联函数在运行时可调试,而宏定义不可以&br&2.编译器会对内联函数的参数类型做安全检查或自动类型转换(同普通函数),而宏定义则不会 &br&3.内联函数可以访问类的成员变量,宏定义则不能 &br&4.在类中声明同时定义的成员函数,自动转化为内联函数。&/p&&p&&br&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/gao/article/details/7397373& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&blog.csdn.net/gao675597&/span&&span class=&invisible&&253/article/details/7397373&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&虚函数&/p&&p&&b&C++多态性 !!!!!&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/hackbuteer1/article/details/7475622& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&blog.csdn.net/hackbutee&/span&&span class=&invisible&&r1/article/details/7475622&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&b&C++对象模型 !!!!!&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=https%3A//www.nowcoder.com/discuss/post%3Fid%3D62368%23_label3& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&http://www.cnblogs.com/QG-whz/p/4909359.html#_label3&/a&&/u&&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/ljianhui/article/details/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&blog.csdn.net/ljianhui/&/span&&span class=&invisible&&article/details/&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/haoel/article/details/1948051& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&blog.csdn.net/haoel/art&/span&&span class=&invisible&&icle/details/1948051&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/taoxu0903/archive//1064234.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&cnblogs.com/taoxu0903/a&/span&&span class=&invisible&&rchive//1064234.html&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/skynet/p/3343726.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&cnblogs.com/skynet/p/33&/span&&span class=&invisible&&43726.html&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&br&&/p&&p&&b&当把一个派生类对象指针赋值给其基类指针时会发生什么样的行为&/b&&/p&&p&当使用基类的指针指向一个派生类的对象时,编译器会安插相应的代码,调整指针的指向,使基类的指针指向派生类对象中其对应的基类子对象的起始处。&/p&&p&这些指针都指向了对应的类型的子对象,且其都包括一个vptr,所以就可以通过虚函数表中的第-1项的type_info对象的地址来获取type_info对象,从而获得类型信息。而这些地址值都是相同的,即指向同一个type_info对象,且该type_info对象显示该对象的类型为Derived,也就能正确地输出其类型信息。&/p&&p&&br&&/p&&p&&b&1.类是怎么通过虚函数实现多态的?&/b&&/p&&p&多态性是“一个接口,多种方法”,多态性分为两类: 静态多态性和动态多态性。以前学过的函数重载和运算符重载实现的多态性属于静态多态性,动态多态性是通过虚函数(virtual function)实现的。静态多态性是指:在程序编译时系统就能决定调用的是哪个函数,因此静态多态性又称编译时的多态性。动态多态性是在程序运行过程中才动态地确定操作所针对的对象。它又称运行时的多态性。类中有虚函数存在,所以编译器就会为他做添加一个vptr指针,并为他们分别创建一个表vtbl,vptr指向那个表,每个类都有自己的vtbl,vtbl的作用就是保存自己类中虚函数的地址,我们可以把vtbl形象地看成一个数组,这个数组的每个元素存放的就是虚函数的地址。,只要vptr不同,指向的vtbl就不同,而不同的vtbl里装着对应类的虚函数地址,所以这样虚函数就可以完成它的任务。子类重写的虚函数的地址直接替换了父类虚函数在虚表中的位置,因此当访问虚函数时,该虚表中的函数是谁的就访问谁。&/p&&p&&b&注意:存在虚函数的类都有一个一维的虚函数表叫做虚表。类的对象有一个指向虚表开始的虚指针。虚表是和类对应的,虚表指针是和对象对应的。&/b&&/p&&p&&b&对于虚函数调用来说,每一个对象内部都有一个虚表指针,该虚表指针被初始化为本类的虚表。所以在程序中,不管你的对象类型如何转换,但该对象内部的虚表指针是固定的,所以呢,才能实现动态的对象函数调用,这就是C++多态性实现的原理&/b&&/p&&p&&b&单继承与多继承:单继承所有的虚函数都包含在虚函数表中,多重继承有多个虚函数表,当子类对父类的虚函数有重写时,子类的函数覆盖父类的函数在对应的虚函数位置,当子类有新的虚函数时,这些虚函数被加在第一个虚函数表的后面&/b&&/p&&p&&b&虚继承:使公共的基类在子类中只有一份,我们看到虚继承在多重继承的基础上多了vbtable来存储到公共基类的偏移&/b&&/p&&p&&br&&/p&&p&&b&虚函数工作原理与内存占用大小&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/hackbuteer1/article/details/7883531& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&blog.csdn.net/hackbutee&/span&&span class=&invisible&&r1/article/details/7883531&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&b&虚继承&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/crystal_avast/article/details/7678704& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&blog.csdn.net/crystal_a&/span&&span class=&invisible&&vast/article/details/7678704&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&b&2.override重写和overload重载的区别&/b&&/p&&p&成员函数被&b&重载&/b&的特征: (1)相同的范围(在同一个类中);&br&(2)函数名字相同;&br&(3)参数不同;&br&(4)virtual关键字可有可无。&/p&&p&函数重载不能靠返回值来进行区分&/p&&p&&b&重写&/b&是指派生类函数重写基类函数,是C++的多态的表现,特征是:&br&(1)不同的范围(分别位于派生类与基类);&br&(2)函数名字相同;&br&(3)参数相同;&/p&&p&(4)返回值(即函数原型)都要与基类的函数相同&br&(5)基类函数必须有virtual关键字。&/p&&p&重写函数的访问修饰符可以不同,尽管virtual函数是private的,在派生类中重写的函数可以是public或protect的&/p&&p&&b&“隐藏&/b&”是指派生类的函数屏蔽了与其同名的基类函数,调用的函数取决于指向它的指针所声明的类型,规则如下:&/p&&p&(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏。&br&(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏。&/p&&p&另一个关于虚函数很微妙的错误情况:参数相同,但是基类的函数是const的,派生类的函数却不是。&/p&&p&(1)一个函数在基类申明一个virtual,那么在所有的派生类都是是virtual的。&br&(2)一个函数在基类为普通函数,在派生类定义为virtual的函数称为越位,函数行为依赖于指针/引用的类型,而不是实际对象的类型。&/p&&p&&br&&/p&&p&可以提及隐藏的问题&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/luxiaoxun/archive//2630751.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&cnblogs.com/luxiaoxun/a&/span&&span class=&invisible&&rchive//2630751.html&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&br&&/p&&p&&b&虚函数与纯虚函数区别?&/b&&/p&&p&1、为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。&br&2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。&br&为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。&/p&&p&纯虚函数最显著的特征是:它们必须在继承类中重新声明函数(不要后面的=0,否则该派生类也不能实例化),而且它们在抽象类中往往没有定义。&br&定义纯虚函数的目的在于,使派生类仅仅只是继承函数的接口。&/p&&p&&br&&/p&&p&定义一个函数为虚函数,不代表函数为不被实现的函数。&br&定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。&br&定义一个函数为纯虚函数,才代表函数没有被实现。&br&定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。纯虚函数最显著的特征是:它们必须在继承类中重新声明函数(不要后面的=0,否则该派生类也不能实例化),而且它们在抽象类中往往没有定义。&/p&&p&1.
虚函数和纯虚函数可以定义在同一个类(class)中,含有纯虚函数的类被称为抽象类(abstract class),而只含有虚函数的类(class)不能被称为抽象类(abstract class)。&/p&&p&2.
虚函数可以被直接使用,也可以被子类(sub class)重载以后以多态的形式调用,而纯虚函数必须在子类(sub class)中实现该函数才可以使用,因为纯虚函数在基类(base class)只有声明而没有定义。&/p&&p&3.
虚函数和纯虚函数都可以在子类(sub class)中被重载,以多态的形式被调用&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/hackbuteer1/article/details/7558868& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&blog.csdn.net/hackbutee&/span&&span class=&invisible&&r1/article/details/7558868&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/bluestorm/archive//2662350.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&cnblogs.com/bluestorm/a&/span&&span class=&invisible&&rchive//2662350.html&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&br&&/p&&p&类型&/p&&p&&b&旧式C转型方式问题&/b&&/p&&p&1.允许任何类型转为任何其他类型。C++每次转型能够更加精确指明意图 如const_cast&/p&&p&2.难以辨别。旧式转型(标识符)组成
C++很多地方都是小括号+对象&/p&&p&&br&&/p&&p&&b&四种类型转换(cast)的关键字详解及代码&/b&&/p&&p&1.&b&static_cast&/b&&/p&&p&最常用的类型转换符,在正常状况下的类型转换,如把int转换为float,如:int i;float f; f=(float)i;或者f=static_cast&float&(i)&/p&&p&2.&b&const_cast&/b&&/p&&p&用于取出const属性,把const类型的指针变为非const类型的指针,如:const int *fun(int x,int y){}  int *ptr=const_cast&int *&(fun(2.3))&/p&&p&3.&b&dynamic_cast&/b&&/p&&p&(1)其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。&br&(2)不能用于内置的基本数据类型的强制转换。&br&(3)dynamic_cast转换如果成功的话返回的是指向类的指针或引用,指针转换失败的话则会返回NULL,引用转换失败抛出异常。&br&(4)使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。&/p&&p&该操作符用于运行时检查该转换是否类型安全,但只在多态类型时合法,即该类至少具有一个虚函数。dynamic_cast与static_cast具有相同的基本语法,dynamic_cast主要用于类层次间的安全的上行转换和下行转换或跨系转型。在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。&/p&&p&4.&b&reinterpret_cast&/b&&/p&&p&这个操作符与编译平台息息相关,不具备移植性&/p&&p&常用于转换函数指针类型。假设有一个数组存储是函数指针,有特定类型。把其他类型的函数指针放入这个数组。
避免使用&/p&&p&interpret是解释的意思,reinterpret即为重新解释,此标识符的意思即为数据的二进制形式重新解释,但是不改变其值。如: char *ptr=&hello freind!&; i=reinterpret_cast&int&(ptr);这个转换方式很少使用。&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/BeyondAnyTime/archive//2652696.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&cnblogs.com/BeyondAnyTi&/span&&span class=&invisible&&me/archive//2652696.html&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/carsonzhu/p/5251012.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&cnblogs.com/carsonzhu/p&/span&&span class=&invisible&&/5251012.html&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&br&&/p&&p&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/zhuyf87/archive//2960899.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&c++ RTTI(运行时类型识别)&/a&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/zhuyf87/archive//2960899.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&cnblogs.com/zhuyf87/arc&/span&&span class=&invisible&&hive//2960899.html&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/nliao/archive//2811401.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&cnblogs.com/nliao/archi&/span&&span class=&invisible&&ve//2811401.html&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/ljianhui/article/details/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&blog.csdn.net/ljianhui/&/span&&span class=&invisible&&article/details/&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&br&&/p&&p&&b&当把一个派生类对象指针赋值给其基类指针时会发生什么样的行为&/b&&/p&&p&当使用基类的指针指向一个派生类的对象时,编译器会安插相应的代码,调整指针的指向,使基类的指针指向派生类对象中其对应的基类子对象的起始处。&/p&&p&这些指针都指向了对应的类型的子对象,且其都包括一个vptr,所以就可以通过虚函数表中的第-1项的type_info对象的地址来获取type_info对象,从而获得类型信息。而这些地址值都是相同的,即指向同一个type_info对象,且该type_info对象显示该对象的类型为Derived,也就能正确地输出其类型信息。&/p&&p&&br&&/p&&p&&b&操作符Operator&/b&&/p&&p&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/zhuyf87/archive//2960899.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&c++隐&/a&&b&式类型转换&/b&&/p&&p&&b&1.可用单个形参来调用的构造函数定义了从形参类型到该类类型的一个隐式转换。&/b&&/p&&p&&b&可通过explicit声明来抑制这种转换,explicit关键字只能用于类内部的构造函数声明上&/b&&/p&&p&2.&b&隐式类型转换操作符
关键词operator之后加一个类型名称&/b&&/p&&p&&b&operator double();
//将Rational转为double&/b&&/p&&p&&br&&/p&&p&&b&最好不要提供任何类型转换函数,根本问题在于未预期的情况下,此类函数可能被调用,而其结果可能不正确、不直观的程序行为。很难调试。解决方法是提供一个对等的函数取代类型转换操作符。&/b&&/p&&p&&b&&u&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/QG-whz/p/4472566.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&cnblogs.com/QG-whz/p/44&/span&&span class=&invisible&&72566.html&/span&&span class=&ellipsis&&&/span&&/a&&/u&&/b&&/p&&p&&br&&/p&&p&&b&&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/zhuyf87/archive//2960899.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&区&/a&别&/b& &b&前置/后置(形式)
++/-- 操作符&/b&&/p&&p&区别前置后置,在后置式有一个int自变量作为形参,并且被调用时,编译器默认为int指定一个0值。&/p&&p&前置返回引用后置必须产生一个临时对象作为返回值,否则i++++;变为合法动作。同时对后置式返回一个const对象禁止以上的动作行为。&/p&&p&&b&千万不要重载&&
|| 操作符&/b&&/p&&p&C++对于 真假值表达式 采用骤死式 评估方式。意思是一旦该表达式的真假值确定,即使表达式中还有部分尚未检验,整个评估工作仍告结束。&/p&&p&例如&/p&&p&char *p;&/p&&p&if((p!=0) && (strlen(p)&10) ...&/p&&p&如果p为空,strlen绝不会调用。否则对于一个null指针调用strlen结果是不可预期。&/p&&p&如果重载&& || 操作符,就没法提供程序员预期的某种行为模式。&/p&&p&&br&&/p&&h2&&b&STL&/b&&/h2&&p&1.&b&STL中的vector:增减元素对迭代器的影响?&/b&&/p&&p&这个问题主要是针对连续内存容器和非连续内存容器。&/p&&p&a、对于连续内存容器,如vector、deque等,增减元素均会使得当前之后的所有迭代器失效。因此,以删除元素为例:由于erase()总是&b&指向被删除元素的下一个元素的有效迭代器&/b&,因此,可以利用该连续内存容器的成员erase()函数的返回值。常见的编程写法为:&/p&&p&&b&[cpp]&/b& &a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/u/article/details/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&view plain&/a& &a href=&https://link.zhihu.com/?ta

我要回帖

更多关于 四则运算去括号 的文章

 

随机推荐