- 引言篇
- 1.C和C++的主要区别是什么?
- 1.C++语言包括过程性语言部分和类部分,过程性语言部分与C并无本质的差别,类部分是C语言中所没有的,它是面向对象程序设计的主体。
- 2.程序设计方法上已从结构化程序设计走向面向对象程序设计了.
- 2.结构程序设计和面向对象程序设计的概念
- 结构化程序设计的主要思想是功能分解并逐步求精。数据与程序分开存储,编程的主要技巧在于追踪哪些函数调用哪些函数,哪些数据发生了变化。
- 面向对象程序设计的本质是把数据和处理数据的过程当成一个整体----对象。(对象是一种特殊变量----像结构体变量、又增加了相关的操作行为)
- 面向对象程序设计的实现需要封装和数据隐藏技术、继承和重用技术、多态性技术。
- 3.什么是类和对象?
- 类是一组性质相同的对象的程序描述,它由概括了一组对象共同性质的数据和函数组成。是封装的基本单元.
- 对象是构成世界的一个独立单位,它具有自己的静态特征(状态)和动态特征(操作)。静态特征即可以用某种数据来描述的特征,动态特征即对象所表现的行为或对象所具有的功能。
- 类与对象的关系:类给出了属于该类的全部对象的抽象定义,而对象则是符合这种定义的一个实体。所以,一个对象又称作类的一个实例(instance)。对象是类的实例,类定义了属于该类的所有对象的共同特性。
- 4. 面向对象程序设计的三大特征是什么?
- 1.封装(encapsulation): 封装是面向对象方法的一个重要原则。它有两个涵义:第一个涵义是,把对象的全部属性和全部服务结合在一起,形成一个不可分割的独立单位(即对象)。第二个涵义也称作“信息隐蔽”,即尽可能隐蔽对象的内部细节,对外形成一个边界(或者说形成一道屏障),只保留有限的对外接口使之与外部发生联系。这主要是指对象的外部不能直接地存取对象地属性,只能通过几个允许外部使用地服务与对象发生联系。
- 2.继承(inheritance): (单继承和多继承)子类可以继承父类中的属性和操作,也可以定义自己的属性和操作
- 3.多态性(polymorphism):在一般类中定义的属性或操作被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或操作名在一般类及其各个特殊类中具有不同的语义。
- 5.类的组成:
- class是定义类的关键字。<类名>是一个标识符,用于惟一标识一个类。一对大括号内是类的说明部分,说明该类的所有成员。类的成员包括数据成员和成员函数两部分。类的成员从访问权限上分有以下三类:公有的(public)、私有的(private)和保护的(protected),其中默认为private权限。
- 1.公有的成员可以被程序中的任何代码访问;
- 2.私有的成员只能被类本身的成员函数及友元类的成员函数访问,其他类的成员函数,包括其派生类的成员函数都不能访问它们;
- 3.保护的成员与私有成员类似,只是除了类本身的成员函数和说明为友元类的成员函数可以访问保护成员外,该类的派生类的成员也可以访问。
- 6.结构体和类的区别是什么?
- 结构和类的唯一区别是:在未指定访问权限时,结构中的成员被默认为公有的而类中的成员被默认为私有的。
- 7.类对象的定义方法和对象成员的表示方法
- 对象的定义方法: <类名><对象名表>;
- 对象成员的表示方法:<对象名>.<成员名>这里的“.”是一个运算符,该运算符的功能是表示对象的成员。或者指向对象的指针的成员表示如下:<对象指针名>-><成员名>
- 8.构造函数和析构函数
- (1)构造函数是一种用于创建对象特殊的成员函数,当创建对象时,系统自动调用构造函数,不能在程序中直接调用。构造函数名与类名相同,一个类可以拥有多个构造函数(重载),构造函数可以有任意类型的参数,但不能具有返回类型。
- (2)析构函数名字为符号“~”加类名,析构函数没有参数和返回值。一个类中只可能定义一个析构函数,所以析构函数不能重载。默认析构函数是一个空函数
- (3)使用构造函数的限制:不能被继承,不能说明为虚函数,不能显式调用,不能取构造函数的地址。
- 9.C++程序的内存布局
- C++程序的内存格局通常分为四个区:
- (1)全局数据区(data area):存放全局变量、静态数据、常量。
- (2)代码区(code area):存放类成员函数、其他函数代码。
- (3)栈区(stack area):存放局部变量、函数参数、返回数据、返回地址。
- (4)堆区 (heap area) :自由存储区。
- 10.拷贝构造函数
- 当构造函数的参数为自身类的引用时,这个构造函数称为拷贝构造函数。拷贝构造函数的功能是用一个已有对象初始化一个正在建立的同类对象。
- 11.this指针
- 当一个成员函数被调用时,自动向它传递一个隐含的参数,该参数是一个指向这个函数成员所在的对象的指针。成员函数中可以用this关键字来引用该指针。this指针的类型就是成员函数所属的类的类型。当调用成员函数时,它被初始化为被调用函数所在的类实例的地址。
- this指针只能在类的成员函数中使用,它指向该成员函数被调用的对象。this指针一般用于返回当前对象自身。this指针大量用于运算符重载成员函数设计中。静态成员函数没有this指针。
- 12.运算符重载
- 运算符的重载形式有两种:重载为类的成员函数和重载为类的友元函数。
- <函数类型> operator <运算符>(<形参表>)或friend <函数类型> operator <运算符>(<形参表>)
- 当运算符重载为类的成员函数时,函数的参数个数比原来的运算数个数要少一个(后缀++、--除外);当重载为类的友元函数时,参数个数与原运算数的个数相同。
- 单目运算符最好重载为成员函数,而双目运算符则最好重载为友元函数。
- 在C++中,单目运算符有++和--(后缀有一个int型的参数,而前缀没有)
- 13. C++中函数重写和重载有何区别?
- 重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有 相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方 法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。
- 继承方式 基类特性 派生类特性
- 公有继承
- Public Public
- Protected Protected
- Private Private
- 私有继承
- Public Private
- Protected Private
- Private 不可访问
- 保护继承
- Public Protected
- Protected Protected
- Private 不可访问
- 14.继承的基本知识
- ①单继承的定义格式如下:
- class<派生类名> :<继承方式><基类名>
- { public:members;//派生类新定义成员
- Private:members;
- Protected:members;
- };
- (1)在公有继承时,派生类的对象可以访问基类中的公有成员;派生类的成员函数可以访问基类中的公有成员和保护成员。这里,一定要区分清楚派生类的对象和派生类中的成员函数对基类的访问是不同的。
- (2)在私有继承时,基类的成员只能由直接派生类访问,而无法再往下继承。
- (3)对于保护继承方式,这种继承方式与私有继承方式的情况相同。两者的区别仅在于对派生类的成员而言,对基类成员有不同的可访问性。
- (4)对于基类中的私有成员,只能被基类中的成员函数和友元函数所访问,不能被其他的函数访问。
- ②派生类对基类成员可以有不同的访问方式:
- 派生类可以覆盖基类成员
- 派生类不能访问基类私有成员
- 基类的公有段和保护段成员访问权对派生类保持不变(公有继承)
- 基类的公有段和保护段成员成为派生类的私有成员(私有继承)
- ③单继承中的构造函数和析构函数
- A.构造函数不能够被继承。派生类构造函数的调用顺序如下:
- (1)调用基类的构造函数,调用顺序按照它们继承时说明的顺序。
- (2)调用子对象类的构造函数,调用顺序按照它们在类中说明的顺序。
- (3)派生类构造函数体中的内容。
- B.析构函数也不能被继承,因此在执行派生类的析构函数时,基类的析构函数也将被调用。执行顺序是先执行派生类的析构函数,再执行基类的析构函数,其顺序与执行构造函数时的顺序正好相反。
- ④赋值兼容规则
- <!--[if !supportLists]-->(1) <!--[endif]-->派生类的对象可以赋值给基类的对象。
- <!--[if !supportLists]-->(2) <!--[endif]-->派生类的对象可以初始化基类的引用
- <!--[if !supportLists]-->(3) <!--[endif]-->派生类的对象的地址可以赋给指向基类的指针。
- 15.多态性与虚函数
- C++的多态性具体体现在运行和编译两个方面,在程序运行时的多态性通过继承和虚函数来体现,而在程序编译时多态性体现在函数和运算符的重载上。
- 重载(函数名相同、参数不同、参数类型不同、返回值无影响)
- 虚函数是在基类中冠以关键字 virtual 的成员函数。它提供了一种接口界面。虚函数可以在一个或多个派生类中被重定义。
- 虚函数的重载函数仍是虚函数。
- 在派生类重定义虚函数时必须有相同的函数原型,包括返回类型,函数名、参数个数、参数类型的顺序必须相同。虚函数必须是类的成员函数。析构函数可以是虚函数,但构造函数不能为虚函数。
- 纯虚函数:在许多情况下,在基类中不能给出有意义的虚函数定义,这时可以把它说明成纯虚函数,把它的定义留给派生类来做。定义纯虚函数的一般形式为:
- class 类名{virtual 返回值类型 函数名(参数表) = 0;};
- 抽象类:如果一个类中至少有一个纯虚函数,那么这个类被成为抽象类(abstract class)。抽象类中不仅包括纯虚函数,也可包括虚函数。抽象类中的纯虚函数可能是在抽象类中定义的,也可能是从它的抽象基类中继承下来且重定义的。
- 抽象类有一个重要特点,即抽象类必须用作派生其他类的基类,而不能用于直接创建对象实例。抽象类不能直接创建对象的原因是其中有一个或多个函数没有定义,但仍可使用指向抽象类的指针支持运行时多态性。
- 16.C++中异常处理的实现
- C++语言异常处理机制的基本思想是将异常的检测与处理分离。
- throw、try和catch。
- 被调用函数直接检测到异常条件的存在并使用throw引发一个异常(注意,C++语言的异常是由程序员控制引发的,而不是由计算机硬件或程序运行环境控制的);在上层调用函数中使用try检测函数调用是否引发异常,检测到的各种异常由catch捕获并作相应处理。
- 1.什么是面向对象的程序设计(OOP)?
- 面向对象的设计方法是一种进行程序设计的新方法,它吸取了结构化程序设计的先进思想,为解决程序结构过于复杂而产生。它的思想是在进行程序设计时,把整个问题分成由相关部分组成的组,每个组考虑和组相关的代码和数据,同时这些分组将按层次关系组织起来,每个分组转换为对象的独立单元。面向对象的程序设计语言都具有多态性、继承性、封装性等特点。
- 基础篇
- 9.通常的C++程序包括哪几部分?
- C++是面向对象的程序设计语言,所以C++程序和C程序在风格上有很大不同。用户编写的C++程序通常分为.cpp和.h两类,.h文件中通常是类的定义,函数原型或说明以及数据的声明等,然后在.cpp文件中通过包含(#include).h文件来使用。一个C++程序的结构通常是:在程序首部是预处理指令,可以声明需要用到的类库或者包含自定义的函数或类的.h文件,定义常量、宏等等。程序的主函数是main()函数,程序将从这里开始执行。
- 10.什么是类型转换?
- int转为float)。有时类型转换会造成数据的丢失。也可以在变量前加(type)来强制使变量转换为需要的类型。比如说某个float类型的变量在输出时需要输出浮点数的信息,而同时它也作为计数值在控制循环次数((int)varname)。
- 11.何时执行构造函数和析构函数?
- 局部对象的构造函数在遇到对象说明语句时执行,并按遇到对象的顺序依次调用,其析构函数则按构造函数的反序进行执行。全局对象的构造函数在main()开始之前执行,并在同一文件中按书写顺序依次执行,但是几个文件之间的全局对象的构造函数执行顺序是不可知的,其析构函数在函数main()结束之后按构造函数反序执行。
- 12. 如何创建数组?
- int array[10]。动态创建数组时数组大小可以是已知的,也可以是变元,此时用动态分配符new来创建,定义形式为type *array=new type[size],当然用完数组时必须用delete[] array来释放空间。由于动态创建数组是分配了一块内存空间,因此当数组较大时最好静态分配。对于多维数组,静态分配同前,动态分配则从最高维开始依次用new分配,释放时则从低维到高维依次delete[]。
- 13.C++会自动检查数组越界吗?
- 回答是否定的,也就是说当你的数组越界使用时编译程序不会报错,而只能是在执行时产生非法操作或者得不到正确结果。因此在使用数组时一定要在编程时自己判断是否越界以保证程序的正确性。
- 14.指针和数组有什么关系?
- int array[10];int* p;p=array;执行后p即指向了数组的第一个元素array[0],最后一个语句相当于p=&array[0](很少这么用)。而任何一个指针变量都可以以数组的方式使用,即通过指针加下标来改变指针的指向。例如定义指针变量int* p;则有p[1]==*(p++)。
- 15.指针使用中应注意哪些问题?
- delete时也容易产生指针错误,delete前一定要确认被释放的指针指向的是有效地址,例如在释放数组时如果忘记了[]将只释放数组的第一个元素所占的空间,而其余元素将被程序"遗忘"在死区,而且很可能当时未被发现,但是如果程序过大或者多次执行将导致资源不足而使系统崩溃。总之由于指针是对内存的直接操作,所以稍不注意就可能产生错误。只有彻底了解指针的使用,并且在编程过程中时刻注意检查指针的指向,指针才会成为有力的工具。
- 16.向函数传递参数有几种方法?有什么不同?
- 向函数传递的参数可以是传值参数,也可以是引用参数,还可能是指针。传值时形式参数即简单的写成type varname,函数执行后将不改变实参的值。引用传递是把变元的地址传给函数,形式参数写成type &varname,调用时则直接写实参的名字即可,因此函数执行后对实参varname的修改将被保留。指针传递就是把变量的指针传给参数,形参形式为type *varname,显然函数将对指针指向的内存地址直接操作,修改将被保留。
- 17.什么是类?
- struct)。从计算机科学的观点来说,一种数据类型应该包括一系列的状态和一系列的操作,操作引起状态的转化。
- 18.什么是对象?
- "int i;",这时我们的意思是,"i是整数类型的一个对象"。在面向对象的C++程序设计中,对象意味着类的实例。
- 19.什么是友元?
- 友元是C++为某个类提供的允许其它类或者函数访问它的机制。友元可以是函数,也可以是类。一个类可以给予它的友元存取和访问自己的特权。
- 20.友元违反数据封装原则吗?
- 恰当地应用友元,不但不会破坏封装性,反而会加强它。
- 在编程的时候,我们经常遇到这样的情况,就是两个类之间有着紧密的联系,它们常常需要互相访问对方的数据和成员函数。实现这种编码的最好方法,就是将这两个类互相设置成友元。
- public的,或者利用public的get()和set()对私有成员进行存取,这样做实际上反而破坏了数据的封装性。采用get()和set()这种存取函数的机制,与直接设置公有数据取得的效果,几乎一样差。它们只是将私有数据成员的名字隐藏了起来,而私有数据成员其他的一切,都暴露出来。
- 同样,将一些函数设置成友元也不会影响类的封装特性。友元函数和类的成员函数一起,构成了类的封装边界。换句话说,友元函数对于封装带来的影响,就如同成员函数的影响一样。谁会说成员函数影响了类的封装性呢?
- 21.构造函数是用来做什么的?
- "构造函数从尘土中建造大楼"。构造函数完成对象的初始化工作,它们将一堆毫无意义的比特转化成一个个活生生的对象。它们为对象初始化各种数据,并分配各种资源,包括内存、文件、socket等等。
- 22.假设List是一个类的名字,那么"List x"和"List x()"之间有区别吗?
- 区别大了!
- 举例说明:函数f()声明了一个List类的局部对象x:
- void f()
- {
- // 局部对象x
- // ...
- }
- 但是,函数g()在内部声明了一个函数x,它返回List的一个对象:
- void g()
- {
- //局部函数,函数名x
- // ...
- }
- 23.析构函数通常做什么工作?
- new,而析构函数用delete。
- 24.编写析构函数时,需要显式调用成员对象的析构函数吗?
- 不需要。
- 类的析构函数自动调用成员对象的析构函数。
- 25.编写派生类的析构函数时,需要显式调用基类的析构函数吗?
- 不需要。
- 派生类的析构函数自动调用基类的析构函数。
- 26.结构和类有什么区别?
- class定义的类中的缺省访问级别是private,而struct定义中缺省级别为public。
- 27.联合与类有什么区别?
- public。如果要求创建的对象的元素共享同一内存地址时就用union来定义该类。但是使用联合定义类时有以下限制:联合不能继承其他的类,也不能被继承,不能含有虚成员函数,不能有静态成员变量,不能有重载运算符"="的对象作成员,不能有含有构造函数和析构函数的对象作成员。
- 28.哪些运算符可以被重载?哪些不能?
- "。" , "?:", "::" 和 "*" 。
- 29.如何进行文件操作?
- 要处理文件I/O,程序首部必须包含头文件fstream.h。其中定义了ifstream,ofstream,fstream等类,它们分别从istream和ostream派生而来,而istream和ostream是从ios派生而来,所以ifstream,ofstream,fstream可以存取ios定义的所有运算。需要注意进行文件操作(打开、读写)时都需要检测操作是否成功以保证程序正确进行处理。
- 30.如何打开和关闭一个文件?
- void open(char *filename,int mode,int access);其中filename为文件名,mode值为文件打开方式,access值为存取文件方式。实际上常常不调用函数open()而直接用ifstream或ofstream的构造函数来打开文件。要关闭一个文件,就用该文件关联的流调用成员函数close()即可。
- 31.如何读写一个文件?
- 读写文本文件时只需将与文件相关联的流与运算符<<、>>连用即可。但是这样读写文本时将发生某些字符转换,为避免这种情况,可采用C++的二进制I/O函数put(),get(),read()和write()。它们的原型即说明如下:
- char &ch);//从流中读入一个字符存入ch中,返回对流的引用。
- char ch); //将ch写入流,返回对流的引用。
- char *buffer,int num);
- //从相关流中读入num个字节存入buffer所指的缓冲区中,返回对流的引用。
- const unsigned char *buffer,int num);
- //把buffer所指的缓冲区中的num个字节写入相关的流中,返回对流的引用。
- 32. 如何判断文件结束?
- 成员函数eof()可以跟踪何时到达文件尾,当到达文件尾时eof()返回值不为0,否则为0。
- 提高篇
- 33.new和delete比 malloc和free有哪些优点?
- new和delete完成与malloc和free相似的功能,但是它们相比之下有以下优点:
- new自动分配空间时容量是自动计算的,不必使用sizeof运算符,所以能够分配到足够的空间以容纳指定类型的对象,避免发生错误。
- new分配内存后将自动返回指定对象类型的指针,而用malloc则需显式的使用强制类型转换。
- new和delete都可以重载,而malloc和free不存在此功能。
- 34. C++中可以使用printf()和scanf()吗?
- "Hello" <<" world!\n"将在屏幕上输出Hello world!并换行。cout,cin与<<和>>连用可以处理C++的任何内部数据类型。与printf和scanf相比它们具有如下优点:安全,编译器会静态地事先得知变量类型而不是由%动态获得;简单快速,不易出错;而通过重载运算符<<和>>,可以对用户定义的对象直接进行输入输出操作,这是printf和scanf所不能及的。
- 35.C++中的输出cout<<能够指定输出数据的域宽和精度吗?
- 可以通过设置格式标志来完成,另外流类ios还有三个成员函数来设置格式参数。它们分别是:
- int width(int w);//设置域宽,w为新域宽,返回以前的域宽。
- int precision(int p);//设置精度,p为设置的精度,返回原来的精度值。
- char fill(char ch);//设置填充字符,ch为新的填充字符,返回原来的值。
- 它们都可以由cout调用。
- 36.如何向函数传递数组?
- void fun(int *x)或者void fun(int x[10])或者void fun(int x[])。这三种方法效果相同,在调用时实参均应该是指向数组的指针。传递多维数组时,除第一维外其余各维大小必须指定,如void fun(int x[][2][6])。
- 37. 我如何才能防止其他的程序员看到我的类的私有成员从而维护数据封装性呢?
- 这个问题本身就存在问题。封装针对的是编码,而不是程序员。
- "私有"这个词是针对类而言的,不是针对你和其他程序员。
- 38.封装是一种安全机制吗?
- 不是。
- 封装并不等于安全。封装是用来防止错误发生的,封装不能用来防间谍。
- 39.可以向构造函数传递变元吗?
- 可以。通过向构造函数传递变元,可以对对象进行特定的初始化。
- 40.如何向函数传递对象?
- 传递对象参数可以和传递其他类型的参数使用相同的方法。对象可以通过传值方式传递给函数,也就是传递给了函数一个拷贝。由于是相当于创建了一个新对象,那么它的构造函数和析构函数是否要执行呢?结果是这样的:新对象没有执行构造函数,但是函数结束时执行了析构函数。原因是新对象应该保持原对象的状态,因此不能执行构造函数重新初始化,而是执行拷贝构造函数,而最后这个拷贝还是要被撤销的,所以要执行析构函数。当然,如果希望对象能够被函数改变也可以向函数传递对象的引用或者指针。
- 41. 为什么友元关系不具有传递性,也不能通过继承得到?
- 很明显,这么做是合情合理的。拿生活中的朋友关系类比:我宣称你是我的朋友,但这并不代表我也认为你的儿女或者你的朋友也是我的朋友。
- class C声明class Base是一个友元类,并且class Derived是class Base的派生类,class Derived并不能自动的成为class C的友元。
- class Bob声明class John是一个友元类,并且class John声明class Salla是一个友元类,class Salla并不能自动的成为class Bob的友元类。
- 42. 如何在一个构造函数的内部调用另一个构造函数?
- 这是不可能办到的。如果你调用了另一个构造函数,编译器将创建一个临时局部对象,而对于当前的对象起不到任何初始化作用。如果想要两个构造函数共享代码,可以创建一个私有成员函数initial(),在两个构造函数中分别调用它即可。
- 43. 对于类C来说,缺省构造函数一定是C::C()的形式吗?
- 不是这样的。
- 缺省构造函数是这样一类构造函数:调用它时可以不给出任何参数。所以不带任何参数的构造函数当然是缺省构造函数,比如:
- class C
- {
- //缺省构造函数
- };
- 但是,缺省构造函数也可以带有参数,只要这些参数都具有缺省值即可,比如:
- class C
- {
- int a=0, int b=0); //缺省构造函数
- };
- 44.为什么含有静态成员的类产生链接错误?
- 产生这种错误的原因通常是编程者没有满足这样一条原则:类的静态数据成员必须被显式的定义,并且只能在一个编译模块中定义一次。如果你违反这一原则,就会得?quot;undefined external" linker error。举例说明:
- // Fred.h
- class Fred {
- public:
- // ...
- private:
- static int j_; // 声明静态数据成员 Fred::j
- // ...
- };
- 你必须在某个文件中定义Fred::j,否则链接不能通过,比如在Fred.cpp文件中定义它:
- // Fred.cpp
- "Fred.h"
- int Fred::j_ = 0;
- 45.局部对象的析构顺序是怎样的?
- 局部对象按照它们建立顺序的反顺序进行析构。最早创建的对象最晚被析构。
- 在下面的例子中,b的析构函数首先被调用,然后是a的析构函数。
- void f()
- {
- C a;
- C b;
- //……
- }
- 46. 能够重载类的析构函数吗?
- 不能。
- 对于一个类来讲,只能有一个析构函数,也一定是class_name::~class_name()的形式。析构函数没有任何参数,也没有返回值。我们不能传递给析构函数什么参数,因为我们不能显式的调用析构函数。
- 47. 如果我的对象是通过new创建的,那么我可以显式的调用析构函数清除这个对象吗?
- 不能。
- delete来清除这个对象。delete操作自动调用相应的析构函数,但是它比析构函数多做了一件重要的事情,它释放了对象本身占有的内存。需要铭记在心的是:delete做了两件事情,它调用了析构函数,并且释放了对象占用的内存。
- 48.说明指针变量和引用变量时,*或&应该与类型名连在一起还是变量名连在一起?
- int* a,b;将会定义一个指针类型变量a和一个整型变量b。因此只要清楚真正的含义,在实际应用时可以灵活一些而不会出错。
- 49. 如何进行操作符重载?
- friend来重载关于类的运算符,这时函数将不是类的成员(没有this指针)。这样重载函数将显式的传递操作数,所以重载单目操作符将有一个参数,而重载双目操作符将有两个参数。但是不能用friend重载=,(),->运算符,而且参数需要是引用类型。
- 50. 在函数定义中使用const修饰符有何作用?
- const可以说明常量,但是在函数定义中有更大的作用。当函数的参数是指针或者引用变量时(非传值参数),如果前面加修饰符const,则可以避免被指向或被引用的变量。当成员函数被const修饰时,例如void fun() const;则表示该函数不会对调用它的对象产生影响。
- 51. 派生类可以继承基类的哪些部分?
- public和protected的成员,派生类都可以继承,但是声明为private的部分,派生类则无权继承,这是为了将来基类中的(私有)成员一旦修改不会影响到其派生类。
- 52. public,protected,private有什么区别?
- public标注的成员具有公有级别,也就是其他函数或者类的对象都可以访问它;private表示私有成员,它们不能被本类以外的对象或者函数引用;protected修饰的成员是保护成员,除了本类或本类的派生类可以存取外其他都无权访问。
- 53. 为什么要使用模板?
- template关键字将不同类型数据的共同操作定义成模板,以后某个类型的数据需要进行这个操作时就可以只指定数据类型以后直接调用该模板。可以编写模板函数,也可以编写模板类(可以根据不同的数据类型生成不同的对象),定义时只需在前面加上template <class T>,T表示程序中待定的数据类型。模板函数在调用时无需显式指定数据类型,直接调用即可;模板类调用时需在程序中需要指定数据类型的尖括号内给出具体的数据类型(如int)。
- 54. C++中可以嵌入汇编吗?
- 可以的,通过关键字asm可以将汇编语言直接嵌到C++程序中。语法为:
- "string")或者asm instru或者asm{instru sequence},其中string,instru,instru sequence都是传给汇编程序的汇编语句。如果对汇编语言很精通,有时候在C++程序中嵌入汇编代码将会大大提高程序的效率。
- 1. 保留字
- C++中,保留字也称关键字,它是预先定义好的标识符。见关键字的解释。
- 2.关键字
- C++中已经被系统定义为特殊含义的一类标识符。C++中的关键字有:
- auto double int struct break else
- long switch case enum register typedef
- char extern return union const float
- short unsigned continue for signed void
- default goto sizeof volatile do if
- static while asm _cs _ds _es
- _ss cdecl far huge interrupt near
- pascal class public private catch protected
- delete new template friend this inline
- throw try operator virtual overload(现不用)
- 3.标识符
- 对变量、函数、标号和其它各种用户自定义对象的命名。在C++中,标识符长度没有限制,第一个字符必须是字母或下划线,其后若有字符则必须为字母、数字或下划线。例如count2,_x是正确的标识符形式,而hello!,3th则是错误的。在C++中标识符区分大小写,另外标识符不能和C++中的关键字相同,也不能和函数同名。
- 4.声明
- 将一个标识符引入一个作用域,此标识符必须指明类型,如果同时指定了它所代表的实体,则声明也是定义。
- 5.定义
- 给所声明的标识符指定所代表的实体。
- 6.变量
- 某个作用域范围内的命名对象。
- 7.常量
- "Please input year:",反斜线字符常量如\n表示回车符。
- 8. const说明符
- const是在变量声明或函数声明时所用到的一个修饰符,用它所修饰的实体具有只读属性。
- 11.流
- 流是既产生信息又消费信息的逻辑设备,通过C++系统和物理设备关联。C++的I/O系统是通过流操作的。有两种类型的流:文本流,二进制流。
- 12.标准输入输出库
- 它是C++标准库的组成部分,为C++语言提供了输入输出的能力。
- 13.内置数据类型
- int、float、double、char 、bool、指针、数组和引用。
- 19.布尔型
- true, false 两种。
- 22.void类型
- 关键字之一,指示没有返回信息。
- 23.结构类型
- public型。大多用作无成员函数的数据结构。
- 24.枚举类型
- 一种用户自定义类型,由用户定义的值的集合组成。
- 25.类型转换
- 一种数据类型转换为另一种,包括显式,隐式两种方式。
- 26.指针
- 一个保存地址或0的对象。
- 27. 函数指针
- 每个函数都有地址,指向函数地址的指针称为函数指针,函数指针指向代码区中的某个函数,通过函数指针可以调用相应的函数。其定义形式为:
- int ( * func ) ( char a, char b);
- 28.引用
- 为一个对象或函数提供的另一个名字。
- 46.new运算符
- 对象创建的操作符。
- 47.delete运算符
- 对象释放操作符,触发析构函数。
- 48.内存泄露
- 操作堆内存时,如果分配了内存,就有责任回收它,否则这块内存就无法重新使用,称为内存泄漏。
- 49.sizeof运算符
- 获得对象在内存中的长度,以字节为单位。
- 50.表达式
- 由操作符和标识符组合而成,产生一个新的值。
- 61.成员函数
- 在类中说明的函数称为成员函数。
- 62.全局函数
- 定义在所有类之外的函数。
- 63.main函数
- 由系统自动调用开始执行C++程序的第一个函数
- 64.外部函数
- extern,表示此函数是外部函数。
- 65.内联函数
- inline说明了一个内联函数,这使一个函数在程序行里进行代码扩展而不被调用。这样的好处是减少了函数调用的开销,产生较快的执行速度。但是由于重复编码会产生较长代码,所以内联函数通常都非常小。如果一个函数在类说明中定义,则将自动转换成内联函数而无需用inline说明。
- 66.函数重载
- 在同一作用域范围内,相同的函数名通过不同的参数类型或参数个数可以定义几个函数,编译时编译器能够识别实参的个数和类型来决定该调用哪个具体函数。需要注意的是,如果两个函数仅仅返回类型不同,则编译时将会出错,因为返回类型不足以提供足够的信息以使编译程序判断该使用哪个函数。所以函数重载时必须是参数类型或者数量不同。
- 67.函数覆盖
- 对基类中的虚函数,派生类以相同的函数名及参数重新实现之。
- 68.函数声明
- 在C++中,函数声明就是函数原型,它是一条程序语句,即它必须以分号结束。它有函数返回类型,函数名和参数构成,形式为:
- 返回类型 function (参数表);
- 参数表包含所有参数的数据类型,参数之间用逗号分开。如下函数声明都是合法的。
- int Area(int length , int width ) ;
- 或 int Area ( int , int ) ;
- 69.函数定义
- 函数定义与函数声明相对应,指函数的具体实现,即包括函数体。如:
- int Area( int length , int width )
- {
- // other program statement
- }
- 70.函数调用
- 指定被调用函数的名字和调用函数所需的信息(参数)。
- 71.函数名
- 与函数体相对,函数调用时引用之
- 72.函数类型
- (1) 获取函数并返回值。
- (2) 获取函数但不返回值。
- (3) 没有获取参数但返回值。
- (4) 没有获取参数也不返回值。
- 73.形式参数
- 函数中需要使用变元时,将在函数定义时说明需要接受的变元,这些变元称为形式参数。形式参数对应于函数定义时的参数说明。其使用与局部变量类似。
- 74.实际参数
- 当需要调用函数时,对应该函数需要的变元所给出的数据称为实际参数。
- 75.值传递
- 函数调用时形参仅得到实参的值,调用结果不会改变实参的值。
- 76.引用传递
- 函数调用时形参为实参的引用,调用结果会改变实参的值。
- 77.递归
- 函数的自我调用称为递归。每次调用是应该有不同的参数,这样递归才能终止。
- 78.函数体
- 与函数名相对,指函数最外边由{}括起来的部分。
- 79.作用域
- 指标识符在程序中有效的范围,与声明位置有关,作用域开始于标识符的生命处。分:局部作用域,函数作用域,函数原型作用域,文件作用域,类作用域。
- 80.局部作用域
- 当标识符的声明出现在由一对花括号所括起来的一段程序内时,该标示符的作用域从声明点开始到块结束处为止,此作用域的范围具有局部性。
- 81.全局作用域
- 标识符的声明出现在函数,类之外,具有全局性。
- 82.类作用域
- 指类定义和相应的成员函数定义范围。
- 83.全局变量
- 定义在任何函数之外,可以被任一模块使用,在整个程序执行期间保持有效。当几个函数要共享同一数据时全局变量将十分有效,但是使用全局变量是有一定弊端的:全局变量将在整个程序执行期间占有执行空间,即使它只在少数时间被用到;大量使用全局变量将导致程序混乱,特别是在程序较复杂时可能引起错误。
- 84.局部变量
- 定义在函数内部的变量。局部变量只在定义它的模块内部起作用,当该段代码结束,这个变量就不存在了。也就是说一个局部变量的生命期就是它所在的代码块的执行期,而当这段代码再次被执行时该局部变量将重新被初始化而不会保持上一次的值。需要注意的是,如果主程序和它的一个函数有重名的变量,当函数被调用时这个变量名只代表当前函数中的变量,而不会影响主程序中的同名变量。
- 85.自动变量
- 由auto修饰,动态分配存储空间,存储在动态存储区中,对他们分配和释放存储空间的工作是由编译系统自动处理的。
- 86.寄存器变量
- 存储在运算器中的寄存器里的变量,可提高执行效率。
- 87.静态变量
- 由连接器分配在静态内存中的变量。
- 88.类
- 一种用户自定义类型,有成员数据,成员函数,成员常量,成员类型组成。类是描叙C++概念的三个基本机制之一。
- 89.外部变量
- extern修饰的变量
- 90.堆
- new 和delete 都是在这里分配和释放内存块。
- 91.栈
- 有两个含义:(1)指内存中为函数维护局部变量的区域。(2)指先进后处的序列。
- 92.抽象类
- 至少包含一个纯虚函数的类。抽象类不能创建对象,但可以创建指向抽象类的指针,多态机制将根据基类指针选择相应的虚函数。
- 93.嵌套类
- 在一个类里可以定义另一个类,被嵌入类只在定义它的类的作用域里有效。
- 94.局部类
- 在函数中定义的类。注意在函数外这个局部类是不可知的。由于局部类的说明有很多限制,所以并不常见。
- 95.基类
- 被继承的类称为基类,又称父类、超类或范化类。它是一些共有特性的集合,可以有其它类继承它,这些类只增加它们独有的特性。
- 96.派生类
- ":被继承类名"即可。
- 97.父类
- 即基类。见95基类的解释。
- 98.子类
- 即派生类。见96派生类的解释。
- 99.对象
- 有两重含义:
- 1. 内存中含有某种数据类型值的邻近的区域。
- 2. 某种数据类型的命名的或未命名的变量。一个拥有构造函数的类型对象在构造函数完成构造之前不能认为是一个对象,在析构函数完成析构以后也不再认为它是一个对象。
- 100. 数据成员
- 指类中存储数据的变量。
- 101.实例化
- 即建立类的一个对象。
- 102.构造函数
- 是一个类的实例的初始化函数,将在生成类的实例时被自动调用,用于完成预先的初始化工作。一个类可以有几个构造函数,以不同的参数来区别,即构造函数可以被重载,以便不同的情况下产生不同的初始化;也可以没有构造函数,此时系统将调用缺省的空构造函数。需要注意的是构造函数没有返回类型。
- 103.成员初始化表
- ":"与构造函数头分开,被初始化的数据成员的值出现在一对括弧之间,它们之间用逗号分开。
- 104.析构函数
- 是一个类的实例的回收函数,将在该实例结束使用前被自动调用,用于完成资源的释放。一个类只可以有一个析构函数,当析构函数执行后,该实例将不复存在。析构函数同样没有返回值。
- 105.虚析构函数
- virtual 修饰的析构函数,当用基类指针释放派生类对象时可根据它所指向的派生类对象释放准确的对象。
- 106.继承
- 面向对象的程序设计语言的特点之一。即一个对象获得另一个对象的特性的过程。如将公共属性和服务放到基类中,而它的各派生类除了有各自的特有属性和服务外还可以共享基类的公共属性和服务。这样的好处是容易建立体系,增强代码重复性。
- 107.单继承
- 一个派生类只有一个基类,成为单继承。
- 108.重继承
- 一个派生类拥有多个基类,成为多继承。
- 109.虚函数
- virtual并在派生类中重定义的函数。重定义将忽略基类中的函数定义,指明了函数执行的实际操作。当一个基类指针指向包含虚函数的派生对象时,C++将根据指针指向的对象类型来决定调用哪一个函数,实现了运行时的多态性。这里的重定义类似于函数重载,不同的是重定义的虚函数的原型必须和基类中指定的函数原型完全匹配。构造函数不能是虚函数,而析构函数则可以是。
- 110.纯虚函数
- 在基类中只有声明没有实现的虚函数。形式为:
- virtual type funname(paralist)=0。这时基函数只提供派生类使用的接口,任何类要使用必须给出自己的定义。
- 111.多态性
- 给不同类型的实体提供单一接口。虚函数通过基类接口实现动态多态性,重载函数和模板提供了静态多态性。
- 112.复制构造函数
- const Z&). 用在同类对象间进行初始化。
- 113.运算符重载
- C++中可以重载双目(如+,×等)和单目(如++)操作符,这样可以使用户像使用基本数据类型那样对自定义类型(类)的变量进行操作,增强了程序的可读性。当一个运算符被重载后,它将具有和某个类相关的含义,同时仍将保持原有含义。
- 114.静态成员函数
- static说明为静态的,但是静态成员函数只能存取类的其他静态成员,而且没有this指针。静态成员函数可以用来在创建对象前预初始化专有的静态数据。
- 115.静态成员变量
- static关键字将使该变量称为静态成员变量,该类所有的对象将共享这个变量的同一拷贝。当对象创建时,所有静态变量只能被初始化为0。使用静态成员变量可以取代全局变量,因为全局变量是违背面向对象的程序设计的封装性的。
- 116.私有成员
- 只能由自身类访问的成员。
- 117.保护成员
- 只能由自身类及其派生类访问的成员。
- 118.友元
- 被某类明确授权可访问其成员的函数和类。
- 119.友元函数
- friend即说明了一个友元函数,友元函数可以存取类的所有私有和保护成员。友元在重载运算符时有时是很有用的。
- 120.友元类
- 被某类明确授权可访问其成员的类
- 121.例外处理
- try., throw , catch组成。
- 122.文件
- 是用于从磁盘文件到终端或打印机的任何东西。流通过完成打开操作与某文件建立联系。
- 0.c/c++中class和struct的区别:
- 关于默认访问权限
- class中默认的成员访问权限是private的,而struct中则是public的。
- 关于继承方式
- class继承默认是private继承,而struct继承默认是public继承。
- extern “C”?
- 答:首先,extern是C/C++语言中表明函数和全局变量作用范围的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。
- 通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。extern "C"是连接申明(linkage declaration),被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:void foo( int x, int y );该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。
- 所以,可以用一句话概括extern “C”这个声明的真实目的:解决名字匹配问题,实现C++与C的混合编程。
- 2.头文件中的ifndef/define/endif有什么作用?
- 答:这是C++预编译头文件保护符,保证即使文件被多次包含,头文件也只定义一次。
- 3. #include<file.h> 与 #include "file.h"的区别?
- 答:前者是从标准库路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。
- 4.评价一下C/C++各自的特点
- 答:C语言是一种结构化语言,面向过程,基于算法和数据结构,所考虑的是如何通过一个过程或者函数从输入得到输出;
- C++是面向对象,基于类、对象和继承,所考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题,通过获取对象的状态信息得到输出或实现过程控制。
- 5.const 有什么用途?
- 答:在C/C++中,(1)可以定义const常量,(2)修饰函数的返回值和形参;
- 在C++中,还可以修饰函数的定义体,定义类的const成员函数。被const修饰的东西受到强制保护,可以预防意外的变动,提高了程序的健壮性。
- 6.const和#define有什么区别?
- 答:(1)const和#define都可以定义常量,但是const用途更广。
- (2)const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
- (3) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。
- 7.关于sizeof小结的。
- 答:sizeof计算的是在栈中分配的内存大小。
- (1) sizeof不计算static变量占得内存;
- (2) 指针的大小一定是4个字节,而不管是什么类型的指针;
- (3) char型占1个字节,int占4个字节,short int占2个字节
- long int占4个字节,float占4字节,double占48字节,string占4字节
- 一个空类占1个字节,单一继承的空类占1个字节,虚继承涉及到虚指针所以占4个字节
- (4) 数组的长度:
- 若指定了数组长度,则不看元素个数,总字节数=数组长度*sizeof(元素类型)
- 若没有指定长度,则按实际元素个数类确定
- Ps:若是字符数组,则应考虑末尾的空字符。
- (5) 结构体对象的长度
- 在默认情况下,为方便对结构体内元素的访问和管理,当结构体内元素长度小于处理器位数的时候,便以结构体内最长的数据元素的长度为对齐单位,即为其整数倍。若结构体内元素长度大于处理器位数则以处理器位数为单位对齐。
- (6) unsigned影响的只是最高位的意义,数据长度不会改变,所以sizeof(unsigned int)=4
- (7) 自定义类型的sizeof取值等于它的类型原型取sizeof
- (8) 对函数使用sizeof,在编译阶段会被函数的返回值的类型代替
- (9) sizeof后如果是类型名则必须加括号,如果是变量名可以不加括号,这是因为sizeof是运算符
- (10) 当使用结构类型或者变量时,sizeof返回实际的大小。当使用静态数组时返回数组的全部大小,sizeof不能返回动态数组或者外部数组的尺寸
- 8.sizeof与strlen的区别?
- 答: (1)sizeof的返回值类型为size_t(unsigned int);
- (2)sizeof是运算符,而strlen是函数;
- (3)sizeof可以用类型做参数,其参数可以是任意类型的或者是变量、函数,而strlen只能用char*做参数,且必须是以’\0’结尾;
- (4)数组作sizeof的参数时不会退化为指针,而传递给strlen是就退化为指针;
- (5)sizeo是编译时的常量,而strlen要到运行时才会计算出来,且是字符串中字符的个数而不是内存大小;
- 9.指针和引用的区别?
- 答:指针和引用都提供了间接操作对象的功能。
- (1) 指针定义时可以不初始化,而引用在定义时就要初始化,和一个对象绑定,而且一经绑定,只要引用存在,就会一直保持和该对象的绑定;
- (2) 赋值行为的差异:指针赋值是将指针重新指向另外一个对象,而引用赋值则是修改对象本身;
- (3) 指针之间存在类型转换,而引用分const引用和非const应用,非const引用只能和同类型的对象绑定,const引用可以绑定到不同但相关类型的对象或者右值
- 10.数组和指针的区别?
- 答:(1)数组要么在全局数据区被创建,要么在栈上被创建;指针可以随时指向任意类型的内存块;
- (2)修改内容上的差别:
- char a[] = “hello”;
- a[0] = ‘X’;
- char *p = “world”; // 注意p 指向常量字符串
- p[0] = ‘X’; // 编译器不能发现该错误,运行时错误
- (3)用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p 所指的内存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
- 11.空指针和悬垂指针的区别?
- 答:空指针是指被赋值为NULL的指针;delete指向动态分配对象的指针将会产生悬垂指针。
- (1) 空指针可以被多次delete,而悬垂指针再次删除时程序会变得非常不稳定;
- (2) 使用空指针和悬垂指针都是非法的,而且有可能造成程序崩溃,如果指针是空指针,尽管同样是崩溃,但和悬垂指针相比是一种可预料的崩溃。
- 12.C++中有malloc/free,为什么还有new/delete?
- 答:malloc/free是C/C++标准库函数,new/delete是C++运算符。他们都可以用于动态申请和释放内存。
- 对于内置类型数据而言,二者没有多大区别。malloc申请内存的时候要制定分配内存的字节数,而且不会做初始化;new申请的时候有默认的初始化,同时可以指定初始化;
- 对于类类型的对象而言,用malloc/free无法满足要求的。对象在创建的时候要自动执行构造函数,消亡之前要调用析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制之内,不能把执行构造函数和析构函数的任务强加给它,因此,C++还需要new/delete。
- 13.什么是智能指针?
- 答:当类中有指针成员时,一般有两种方式来管理指针成员:一是采用值型的方式管理,每个类对象都保留一份指针指向的对象的拷贝;另一种更优雅的方式是使用智能指针,从而实现指针指向的对象的共享。
- 智能指针的一种通用实现技术是使用引用计数。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。
- 每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。
- 14.面向对象技术的基本概念是什么,三个基本特征是什么?
- 答:基本概念:类、对象、继承; 基本特征:封装、继承、多态。
- 封装:将低层次的元素组合起来形成新的、更高实体的技术;
- 继承:广义的继承有三种实现形式:实现继承、可视继承、接口继承。
- 多态:允许将子类类型的指针赋值给父类类型的指针
- 15.C++空类默认有哪些成员函数?
- 答:默认构造函数、析构函数、复制构造函数、赋值函数
- 16.哪一种成员变量可以在一个类的实例之间共享?
- 答:static静态成员变量
- 17.继承层次中,为什么基类析构函数是虚函数?
- 答:编译器总是根据类型来调用类成员函数。但是一个派生类的指针可以安全地转化为一个基类的指针。这样删除一个基类的指针的时候,C++不管这个指针指向一个基类对象还是一个派生类的对象,调用的都是基类的析构函数而不是派生类的。如果你依赖于派生类的析构函数的代码来释放资源,而没有重载析构函数,那么会有资源泄漏。
- 18.为什么构造函数不能为虚函数?
- 答:虚函数采用一种虚调用的方法。需调用是一种可以在只有部分信息的情况下工作的机制。如果创建一个对象,则需要知道对象的准确类型,因此构造函数不能为虚函数。
- 19.如果虚函数是有效的,那为什么不把所有函数设为虚函数?
- 答:不行。首先,虚函数是有代价的,由于每个虚函数的对象都要维护一个虚函数表,因此在使用虚函数的时候都会产生一定的系统开销,这是没有必要的。
- 20.构造函数可以是内联函数
- 21.什么是多态?多态有什么作用?
- 答:多态就是将基类类型的指针或者引用指向派生类型的对象。多态通过虚函数机制实现。
- 多态的作用是接口重用。
- 22.重载和覆盖有什么区别?
- 答:虚函数是基类希望派生类重新定义的函数,派生类重新定义基类虚函数的做法叫做覆盖;
- 重载就在允许在相同作用域中存在多个同名的函数,这些函数的参数表不同。重载的概念不属于面向对象编程,编译器根据函数不同的形参表对同名函数的名称做修饰,然后这些同名函数就成了不同的函数。
- 重载的确定是在编译时确定,是静态的;虚函数则是在运行时动态确定。
- 23.公有继承、受保护继承、私有继承
- 答:(1)公有继承时,派生类对象可以访问基类中的公有成员,派生类的成员函数可以访问基类中的公有和受保护成员;
- (2)私有继承时,基类的成员只能被直接派生类的成员访问,无法再往下继承;
- (3)受保护继承时,基类的成员也只被直接派生类的成员访问,无法再往下继承。
- 24.公有继承时基类受保护的成员,可以通过派生类对象访问但不能修改。
- 25.有哪几种情况只能用构造函数初始化列表而不能用赋值初始化?
- 答:const成员,引用成员
- 26.什么是虚指针?
- 答:虚指针或虚函数指针是虚函数的实现细节。带有虚函数的每一个对象都有一个虚指针指向该类的虚函数表。
- 27.C++如何阻止一个类被实例化?一般在什么时候将构造函数声明为private?
- 答:(1)将类定义为抽象基类或者将构造函数声明为private;
- (2)不允许类外部创建类对象,只能在类内部创建对象
- 28.main函数执行之前会执行什么?执行之后还能执行代码吗?
- 答:(1)全局对象的构造函数会在main函数之前执行;
- (2)可以,可以用_onexit 注册一个函数,它会在main 之后执行;
- 29.请描述进程和线程的区别?
- 答:(1)进程是程序的一次执行,线程是进程中的执行单元;
- (2)进程间是独立的,这表现在内存空间、上下文环境上,线程运行在进程中;
- (3)一般来讲,进程无法突破进程边界存取其他进程内的存储空间;而同一进程所产生的线程共享内存空间;
- (4)同一进程中的两段代码不能同时执行,除非引入多线程。
- 30.进程间如何通信?
- 答:信号、信号量、消息队列、共享内存
- 31.在网络编程中涉及并发服务器,使用多进程与多线程的区别?
- 答:(1)线程执行开销小,但不利于资源管理和保护;进程则相反,进程可跨越机器迁移。
- (2)多进程时每个进程都有自己的内存空间,而多线程间共享内存空间;
- (3)线程产生的速度快,线程间通信快、切换快;
- (4)线程的资源利用率比较好;
- (5)线程使用公共变量或者资源时需要同步机制。
- 32.说一下TCP 3次握手、4次挥手的全过程。
- 33.TCP和UDP有什么区别。
- 答:
- TCP——传输控制协议,提供的是面向连接、可靠的字节流服务。
- 当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。
- UDP——用户数据报协议,是一个简单的面向数据报的传输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快.
- TCP协议和UDP协议的一些特性区别如下:
- 1.TCP协议在传送数据段的时候要给段标号;UDP 协议不需要。
- 2.TCP协议可靠;UDP协议不可靠。
- 3.TCP协议是面向连接;UDP协议采用无连接。
- 4.TCP协议负载较高,采用虚电路;UDP协议低负载。
- 5.TCP协议的发送方要确认接受方是否收到数据段(3次握手协议)。
- 6.TCP协议采用窗口技术和流控制。
- 34.如何编写套接字?
- 35.调用函数时要进行参数压栈,一般情况下顺序是从最右边参数往左压栈。
- 36.经常要操作的内存分为那几个类别?
- 答:(1)栈区:由编译器自动分配和释放,存放函数的参数值、局部变量的值等;
- (2)堆:一般由程序员分配和释放,存放动态分配的变量;
- (3)全局区(静态区):全局变量和静态变量存放在这一块,初始化的和未初始化的分开放;
- (4)文字常量区:常量字符串就放在这里,程序结束自动释放;
- (5)程序代码区:参访函数体的二进制代码。
- 37.请讲述堆和栈的区别。
- 答:(1)申请方式不同。栈上有系统自动分配和释放;堆上有程序员自己申请并指明大小;
- (2)栈是向低地址扩展的数据结构,大小很有限;堆是向高地址扩展,是不连续的内存区域,空间相对大且灵活;
- (3)栈由系统分配和释放速度快;堆由程序员控制,一般较慢,且容易产生碎片;
- 38.全局变量放在数据段,内部变量static int count;放在数据段,内部变量char *p=“AAA”,p的位置在堆栈上,指向的空间的位置数据段,内部变量char *p=new char;p的位置堆,指向的空间的位置数据段
- 39.字符数组与字符串的比较:最明显的区别是字符串会在末尾自动添加空字符。
- 40.函数指针相关概念(C++学习笔记)
- 41.类使用static成员的优点,如何访问?
- 答:优点:
- (1)static 成员的名字是在类的作用域中,因此可以避免与其他类的成员或全局对象名字冲突;
- (2)可以实施封装。static 成员可以是私有成员,而全局对象不可以;
- (3) static 成员是与特定类关联的,可清晰地显示程序员的意图。
- static 数据成员必须在类定义体的外部定义(正好一次),static 关键字只能用于类定义体内部的声明中,定义不能标示为static. 不像普通数据成员,static成员不是通过类构造函数进行初始化,也不能在类的声明中初始化,而是应该在定义时进行初始化.保证对象正好定义一次的最好办法,就是将static 数据成员的定义放在包含类非内联成员函数定义的文件中。
- 静态数据成员初始化的格式为:
- <数据类型><类名>::<静态数据成员名>=<值>
- 类的静态数据成员有两种访问形式:
- <类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
- 42. static数据成员和static成员函数
- 答:(1)static数据成员:
- static数据成员独立于该类的任意对象而存在;每个static数据成员是与类关联的对象,并不与该类的对象相关联。Static数据成员(const static数据成员除外)必须在类定义体的外部定义。不像普通数据成员,static成员不是通过类的构造函数进行初始化,而是应该在定义时进行初始化。
- (2)static成员函数:
- Static成员函数没有this形参,它可以直接访问所属类的static成员,不能直接使用非static成员。因为static成员不是任何对象的组成部分,所以static成员不能被声明为const。同时,static成员函数也不能被声明为虚函数。
- 43.static成员变量定义放在cpp文件中,不能放在初始化列表中。Const static成员可就地初始化。
- 44.如何引用一个已经定义过的全局变量?
- 答:可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变量,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。
- 44.static关键字的作用。
- 答:static总是使得变量或对象的存储形式变成静态存储,连接方式变成内部连接,对于局部变量(已经是内部连接了),它仅改变其存储方式;对于全局变量(已经是静态存储了),它仅改变其连接类型。
- 45.奈奎斯特定理
- 46.香农定理
- 47.多态类中的虚函数表是 Compile-Time,还是 Run-Time时建立的?
- 答案:虚拟函数表是在编译期就建立了,各个虚拟函数这时被组织成了一个虚拟函数的入口地址的数组。而对象的隐藏成员--虚拟函数表指针是在运行期--也就是构造函数被调用时进行初始化的,这是实现多态的关键。
- 48. 一个父类写了一个 virtual 函数,如果子类覆盖它的函数不加 virtual ,也能实现多态?
- 在子类的空间里,有没有父类的这个函数,或者父类的私有变量? (华为笔试题)
- 答案:只要基类在定义成员函数时已经声明了 virtue关键字,在派生类实现的时候覆盖该函数时,virtue关键字可加可不加,不影响多态的实现。子类的空间里有父类的所有变量(static除外)。
- 49. 完成字符串拷贝可以使用 sprintf、strcpy 及 memcpy 函数,请问这些函数有什么区别
- ,你喜欢使用哪个,为什么?
- 答案:这些函数的区别在于 实现功能以及操作对象不同。
- (1)strcpy 函数操作的对象是字符串,完成从源字符串到目的字符串的拷贝功能。
- (2)sprintf 函数操作的对象不限于字符串:虽然目的对象是字符串,但是源对象可以是字符串、也可以是任意基本类型的数据。这个函数主要用来实现(字符串或基本数据类型)向字符串的转换功能。如果源对象是字符串,并且指定 %s 格式符,也可实现字符串拷贝功能。
- (3)memcpy 函数顾名思义就是内存拷贝,实现将一个内存块的内容复制到另一个内存块这一功能。内存块由其首地址以及长度确定。程序中出现的实体对象,不论是什么类型,其最终表现就是在内存中占据一席之地(一个内存区间或块)。因此,memcpy 的操作对象不局限于某一类数据类型,或者说可适用于任意数据类型,只要能给出对象的起始地址和内存长度信息、并且对象具有可操作性即可。鉴于memcpy 函数等长拷贝的特点以及数据类型代表的物理意义,memcpy 函数通常限于同种类型数据或对象之间的拷贝,其中当然也包括字符串拷贝以及基本数据类型的拷贝。
- 对于字符串拷贝来说,用上述三个函数都可以实现,但是其实现的效率和使用的方便程度不同:
- • strcpy 无疑是最合适的选择:效率高且调用方便。
- • sprintf 要额外指定格式符并且进行格式转化,麻烦且效率不高。
- • memcpy 虽然高效,但是需要额外提供拷贝的内存长度这一参数,易错且使用不便;并且如果长度指定过大的话(最优长度是源字符串长度 + 1),还会带来性能的下降。其实 strcpy 函数一般是在内部调用 memcpy 函数或者用汇编直接实现的,以达到高效的目的。因此,使用 memcpy 和 strcpy 拷贝字符串在性能上应该没有什么大的差别。
- 对于非字符串类型的数据的复制来说,strcpy 和 snprintf 一般就无能为力了,可是对 memcpy 却没有什么影响。但是,对于基本数据类型来说,尽管可以用 memcpy 进行拷贝,由于有赋值运算符可以方便且高效地进行同种或兼容类型的数据之间的拷贝,所以这种情况下 memcpy 几乎不被使用 。memcpy 的长处是用来实现(通常是内部实现居多)对结构或者数组的拷贝,其目的是或者高效,或者使用方便,甚或两者兼有。
- 50. 应用程序在运行时的内存包括代码区和数据区,其中数据区又包括哪些部分?
- 答:对于一个进程的内存空间而言,可以在逻辑上分成 3个部份:代码区,静态数据区和动态数据区。
- 动态数据区一般就是“堆栈”。 栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”。
- 全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。程序通过堆栈的基地址和偏移量来访问本地变量。
- 51. C++函数中值的传递方式有哪几种?
- 答:三种传递方式为:值传递、指针传递和引用传递。
- 52. C++里面是不是所有的动作都是main()引起的?如果不是,请举例.
- 比如全局变量的初始化,就不是由main函数引起的
- 举例: class A{};
- A a; //a的构造函数限执行
- int main() {}
- 53. 下列哪两个是等同的
- int b;
- A const int* a = &b;
- B const* int a = &b;
- C const int* const a = &b;
- D int const* const a = &b;
- 54. 内联函数在编译时是否做参数类型检查?
- 答:内联函数要做参数类型检查, 这是内联函数跟宏相比的优势。
- 55. 全局变量和局部变量有什么区别?实怎么实现的?操作系统和编译器是怎么知道的?
- (1)生命周期不同:
- 全局变量随主程序创建和创建,随主程序销毁而销毁
- 局部变量在局部函数内部,甚至局部循环体等内部存在,退出就不存在; 内存中
- 分配在全局数据区
- (2)使用方式不同:通过声明后全局变量程序的各个部分都可以用到;局部变量只能在局部使用,分配在栈区
- 操作系统和编译器通过内存分配的位置来知道的,全局变量分配在全局数据段并且在程序开始运行的时候被加载。局部变量则分配在堆栈里面 。
- 57. static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
- 答:static全局变量与普通全局变量区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
- static局部变量和普通局部变量区别:static局部变量只被初始化一次,下一次依据上一次结果值;
- static函数与普通函数区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。
- 58. 程序的局部变量存在于(堆栈)中,全局变量存在于(静态区 )中,动态申请数据存在于( 堆)中。
- 59. 对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
- c用宏定义,c++用inline
- 60. 有1,2,....一直到n的无序数组,求排序算法,并且要求时间复杂度为O(n),空间复杂度O(1),使用交换,而且一次只能交换两个数。
- #include<iostream.h>
- Using namespace std;
- int main(){
- int a[] = {10,6,9,5,2,8,4,7,1,3};
- int len = sizeof(a) / sizeof(int);
- int temp;
- for(int i = 0; i < len; )
- {
- temp = a[a[i] - 1];
- a[a[i] - 1] = a[i];
- a[i] = temp;
- if ( a[i] == i + 1)
- i++;
- }
- for (int j = 0; j < len; j++)
- cout<<a[j]<<",";
- return 0;
- }
c++基本知识点
转载wx638ef1cfb1448 博主文章分类:C、C++、Java
上一篇:linux下vim配置
下一篇:用Java23种设计模式泡MM
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
linux基本知识点
硬件信息 \--> 硬盘 \-> ide 硬盘 (链接 ide 接口) 100M/s \-> scsi 硬盘 (链接 sc
linux 硬盘 接口 知识点 primary -
IGMP 基本知识点
IGMP 三个版本的基本知识点
组播 IGMP -
shell命令基本知识点
shell基本知识点整理
shell 基本知识 -
springmvc基本知识点
springmvc高级知识:
spring mvc 分享