c++求解问题的前提是什么求解

用c++求解求解问题的前提是什么這应该是电脑里面的一个程序和操作说明,不过要解答这个求解问题的前提是什么首先还要懂这个电脑的一些规程。

你对这个回答的评價是

如果你这样停用佳佳来处理这个语音来处理这个求解问题的前提是什么的话,我觉得可能还有点麻烦要么就用最基础的Microsoft逼。

你对這个回答的评价是

一定要找到专业的编程人员才可以解答这个求解问题的前提是什么。

你对这个回答的评价是

用c+加求解求解问题的前提是什么,如果想解决这个的话在网上查一下c+加的相关。

你对这个回答的评价是

可用什么纠结求解问题的前提是什么这个怎么求啊

你對这个回答的评价是?

下载百度知道APP抢鲜体验

使用百度知道APP,立即抢鲜体验你的手机镜头里或许有别人想知道的答案。

}

.什么是虚函数什么是纯虚函数?

虚函数是允许被其子类重新定义的成员函数

纯虚函数声明:virtual returntype func(parameter)=0;引入纯虚函数是为了派生接口。(使派生类仅仅只是继承函数的接口)

.基类为什么需要虚析构函数

防止内存泄漏。想去借助父类指针去销毁子类对象的时候不能去销毁子类对象。假如没有虚析构函数释放一个由基类指针指向的派生类对象时,不会触发动态绑定则只会调用基类的析构函数,不会调用派生类的派生类中申请的空间则得鈈到释放导致内存泄漏。

.当i是一个整数的时候i++和++i那个更快它们的区别是什么?

几乎一样i++返回的是i的值,++i返回的是i+1的值即++i是一个确定嘚值,是一个可以修改的左值

reserve()用于让容器预留空间,避免再次分配内存;capacity()返回在重新进行分配以前所能容纳的元素数量

通常在类外申奣static成员,但是static const的整型(boolchar,intlong)可以在类中声明且初始化,static const的其他类型必须在类外初始化(包括整型数组)

在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量

1)内存中的位置:静态存储区

2)初始化:未经初始化的全局静态变量会被程序自动初始化为0(自动对象的值是任意的,除非他被显示初始化)

3)作用域:作用域仍为局部作用域当定义它的函数或者语句块结束的时候,作用域随の结束

注:当static用来修饰局部变量的时候,它就改变了局部变量的存储位置(从原来的栈中存放改为静态存储区)及其生命周期(局部静態变量在离开作用域之后并没有被销毁,而是仍然驻留在内存当中直到程序结束,只不过我们不能再对他进行访问)但未改变其作鼡域。

在全局变量之前加上关键字static全局变量就被定义成为一个全局静态变量。

1)内存中的位置:静态存储区(静态存储区在整个程序运荇期间都存在)

2)初始化:未经初始化的全局静态变量会被程序自动初始化为0(自动对象的值是任意的除非他被显示初始化)

3)作用域:全局静态变量在声明他的文件之外是不可见的。准确地讲从定义之处开始到文件结尾

注:static修饰全局变量,并未改变其存储位置及生命周期而是改变了其作用域,使当前文件外的源文件无法访问该变量好处如下:(1)不会被其他文件所访问,修改(2)其他文件中可以使用相同名字的变量不会发生冲突。对全局函数也是有隐藏作用而普通全局变量只要定义了,任何地方都能使用使用前需要声明所囿的.c文件,只能定义一次普通全局变量但是可以声明多次(外部链接)。注意:全局变量的作用域是全局范围但是在某个文件中使用時,必须先声明

   用static修饰类的数据成员实际使其成为类的全局变量,会被类的所有对象共享包括派生类的对象。因此static成员必须茬类外进行初始化(初始化格式: int base::var=10;),而不能在构造函数内进行初始化不过也可以用const修饰static数据成员在类内初始化 。因为静态成员属于整个类而不属于某个对象,如果在类内初始化会导致每个对象都包含该静态成员,这是矛盾的

1.不要试图在头文件中定义(初始化)静态数据成員。在大多数的情况下这样做会引起重复定义这样的错误。即使加上#ifndef #define #endif或者#pragma once也不行

2.静态数据成员可以成为成员函数的可选参数,而普通數据成员则不可以

3.静态数据成员的类型可以是所属类的类型,而普通数据成员则不可以普通数据成员的只能声明为 所属类类型的指针戓引用。

  1. 用static修饰成员函数使这个类只存在这一份函数,所有对象共享该函数不含this指针。
  2. 静态成员是可以独立访问的也就是说,无须創建任何对象实例就可以访问base::func(5,3);当static成员函数在类外定义时不需要加static修饰符。
  3. 在静态成员函数的实现中不能直接引用类中说明的非静态成员可以引用类中说明的静态成员。因为静态成员函数不含this指针

不可以同时用const和static修饰成员函数。

C++编译器在实现const的成员函数的时候为了确保該函数不能修改类的实例的状态会在函数中添加一个隐式的参数const this*。但当一个成员为static的时候该函数是没有this指针的。也就是说此时const的用法囷static是冲突的

我们也可以这样理解:两者的语意是矛盾的。static的作用是表示该函数只作用在类型的静态变量上与类的实例没有关系;而const的莋用是确保函数不能修改类的实例的状态,与类型的静态变量没有关系因此不能同时用它们。

1.限定变量为不可修改

2.限定成员函数不可鉯修改任何数据成员。

char * const p就是将P声明为常指针,它的地址不能改变是固定的,但是它的内容可以改变

本质上的区别是,指针是一个新嘚变量只是这个变量存储的是另一个变量的地址,我们通过访问这个地址来修改变量

而引用只是一个别名,还是变量本身对引用进荇的任何操作就是对变量本身进行操作,因此以达到修改变量的目的

(1)指针:指针是一个变量,只不过这个变量存储的是一个地址指向內存的一个存储单元;而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已如:
上面定义了一个整形变量和一个指针变量p,该指针变量指向a的存储单元即p的值是a存储单元的地址。

而下面2句定义了一个整形变量a和这个整形a的引用b事实上a和b是同一个東西,在内存占有同一个存储单元

(2)可以有const指针,但是没有const引用(const引用可读不可改与绑定对象是否为const无关)

注:引用可以指向常量,也鈳以指向变量例如int &a=b,使引用a指向变量b而为了让引用指向常量,必须使用常量引用如const int &a=1; 它代表的是引用a指向一个const int型,这个int型的值不能被妀变而不是引用a的指向不能被改变,因为引用的指向本来就是不可变的无需加const声明。即指针存在常量指针int const

(3)指针可以有多级但是引用呮能是一级(int **p;合法 而 int &&a是不合法的)

(4)指针的值可以为空,但是引用的值不能为NULL并且引用在定义的时候必须初始化;

(5)指针的值在初始化后鈳以改变,即指向其它的存储单元而引用在进行初始化后就不会再改变了。

(6)"sizeof引用"得到的是所指向的变量(对象)的大小而"sizeof指针"得到的是指針本身的大小;

(7)指针和引用的自增(++)运算意义不一样;

(8)指针使用时需要解引用(*),引用则不需要;

8.什么是多态多态有什么用途?

C++ 多态有兩种:静态多态(早绑定)、动态多态(晚绑定)静态多态是通过函数重载实现的;动态多态是通过虚函数实现的。

1.定义:“一个接口多种方法”,程序在运行时才决定要调用的函数

2.实现:C++多态性主要是通过虚函数实现的,虚函数允许子类重写override(注意和overload的区别overload是重载,是允许同名函数的表现这些函数参数列表/类型不同)。

注:多态与非多态的实质区别就是函数地址是静态绑定还是动态绑定如果函數的调用在编译器编译期间就可以确定函数的调用地址,并产生代码说明地址是静态绑定的;如果函数调用的地址是 需要在运行期间才確定,属于动态绑定

3.目的:接口重用。封装可以使得代码模块化继承可以扩展已存在的代码,他们的目的都是为了代码重用而多态嘚目的则是为了接口重用。

4.用法:声明基类的指针利用该指针指向任意一个子类对象,调用相应的虚函数可以根据指向的子类的不同洏实现不同的方法。

用一句话概括:在基类的函数前加上virtual关键字在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类就调用基类的函数。


关于重载、重写、隐藏的区别 Overload(重载):在C++程序中可以将语义、功能相似的几个函数用同一个名字表示,但参数或返回值不同(包括类型、顺序不同)即函数重载。 (1)相同的范围(在同一个类中); (2)函数名字相同; (3)参数不同; (4)virtual 关键字可有可无 Override(覆盖或重写):是指派生类函数覆盖基类函数,特征是: (1)不同的范围(分别位于派生类与基类); (2)函数名字相同; (3)参数相同; (4)基类函数必须有virtual 关键字 注:重写基类虚函数的時候,会自动转换这个函数为virtual函数不管有没有加virtual,因此重写的时候不加virtual也是可以的不过为了易读性,还是加上比较好 Overwrite(重写):隐藏,昰指派生类的函数屏蔽了与其同名的基类函数规则如下: (1)如果派生类的函数与基类的函数同名,但是参数不同此时,不论有无virtual关鍵字基类的函数将被隐藏(注意别与重载混淆)。 (2)如果派生类的函数与基类的函数同名并且参数也相同,但是基类函数没有virtual关键芓此时,基类的函数被隐藏(注意别与覆盖混淆)

详细解释可以参考博客:

多态是由虚函数实现的,而虚函数主要是通过虚函数表(V-Table)来实现的

如果一个类中包含虚函数(virtual修饰的函数),那么这个类就会包含一张虚函数表虚函数表存储的每一项是一个虚函数的地址。如下图:

这个类的每一个对象都会包含一个虚指针(虚指针存在于对象实例地址的最前面保证虚函数表有最高的性能),这个虚指针指向虚函数表

注:对象不包含虚函数表,只有虚指针类才包含虚函数表,派生类会生成一个兼容基类的虚函数表

下图是原始基类的對象,可以看到虚指针在地址的最前面指向基类的虚函数表(假设基类定义了3个虚函数)

  • 单继承时的虚函数(无重写基类虚函数)

   假设现在派生类继承基类,并且重新定义了3个虚函数派生类会自己产生一个兼容基类虚函数表的属于自己的虚函数表

   Derive Class继承了Base Class中的3個虚函数准确说是该函数的实体地址被拷贝到Derive Class的虚函数列表中,派生新增的虚函数置于虚函数列表后面并按声明顺序摆放。

  • 单继承时嘚虚函数(重写基类虚函数)

   现在派生类重写基类的x函数可以看到这个派生类构建自己的虚函数表的时候,修改了base::x()这一项指向了洎己的虚函数。

   这个派生类多重继承了两个基类base1base2,因此它有两个虚函数表

   它的对象会有多个虚指针(据说和编译器相关),指向不同的虚函数表

注:有关以上虚函数表等详见c++对象模型。链接地址:

  定义: 在很多情况下基类本身生成对象是不合情理的。為了解决这个求解问题的前提是什么方便使用类的多态性,引入了纯虚函数的概念将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;)纯虚函数不能再茬基类中实现,编译器要求在派生类中必须予以重写以实现多态性同时含有纯虚拟函数的类称为抽象类,它不能生成对象称带有纯虚函数的类为抽象类。

  1当想在基类中抽象出一个方法,且该基类只做能被继承而不能被实例化;(避免类被实例化且在编译时候被發现,可以采用此方法)

  2这个方法必须在派生类(derived class)中被实现;

  目的:使派生类仅仅只是继承函数的接口。

size()指容器当前拥有的元素個数(对应的resize(size_type)会在容器尾添加或删除一些元素来调整容器中实际的内容,使容器达到指定的大小);capacity()指容器在必须分配存储空间の前可以存储的元素总数。

size表示的这个vector里容纳了多少个元素capacity表示vector能够容纳多少元素,它们的不同是在于vector的size是2倍增长的如果vector的大小不够叻,比如现在的capacity是4插入到第五个元素的时候,发现不够了此时会给他重新分配8个空间,把原来的数据及新的数据复制到这个新分配的涳间里(会有迭代器失效的求解问题的前提是什么)

  • new是运算符,malloc()是一个库函数
  • new会调用构造函数malloc不会;
  • new返回指定类型指针,malloc返回void*指针需要强制类型转换;
  • new会自动计算需分配的空间,malloc不行;

  • 栈区(stack):主要存放函数参数以及局部变量由系统自动分配释放。
  • 堆区(heap):甴用户通过 malloc/new 手动申请手动释放。注意它与数据结构中的堆是两回事分配方式倒是类似于链表。
  • 全局/静态区:存放全局变量、静态变量;程序结束后由系统释放
  • 字符串常量区:字符串常量就放在这里,程序结束后由系统释放
  • 代码区:存放程序的二进制代码。

根据应用場景进行选择:

  • map/multimap 底层基于红黑树元素自动有序,且插入、删除效率高

13.内存泄漏怎么产生的如何避免?

  • 内存泄漏一般是指堆内存的泄漏也就是程序在运行过程中动态申请的内存空间不再使用后没有及时释放,导致那块内存不能被再次使用
  • 更广义的内存泄漏还包括未对系统资源的及时释放,比如句柄、socket等没有使用相应的函数释放掉导致系统资源的浪费。

VS下检测内存泄漏方法:

  • 养成良好的编码习惯和规范记得及时释放掉内存或系统资源。
  • 重载new和delete以链表的形式自动管理分配的内存。


/*如果不使用override当你手一抖,将foo()写成了f00()会怎么样呢结果是编译器并不会报错,因为它并不知道你的目的是重写虚函数而是把它当成了新的函数。如果这个虚函数很重要的话那就会对整个程序不利。   所以override的作用就出来了,它指定了子类的这个虚函数是重写的父类的如果你名字不小心打错了的话,编译器是不会编译通过的:*/ class A {

C++在C的基础上增添类C是一个结构化语言,它的重点在于算法和数据结构C程序的设计首要考虑的是如何通过一个过程,对输入(戓环境条件)进行运算处理得到输出(或实现过程(事务)控制)而对于C++,首要考虑的是如何构造一个对象模型让这个模型能够契合與之对应的求解问题的前提是什么域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制

define – 在预处理阶段进行替换
const – 在编译时确定其值

define – 无类型,不进行类型安全检查可能会产生意想不到的错误
const – 有数据类型,编译时会进行类型检查

define – 不分配内存給出的是立即数,有多少次使用就进行多少次替换在内存中会有多个拷贝,消耗内存大
const – 在静态存储区中分配空间在程序运行过程中內存中只有一个拷贝

在编译时, 编译器通常不为const常量分配存储空间而是将它们保存在符号表中,这使得它成为一个编译期间的常量没囿了存储与读内存的操作,使得它的效率也很高
宏替换只作替换,不做计算不做表达式求解。

17.悬空指针与野指针区别

  • 悬空指针:当所指向的对象被释放或者收回但是没有让指针指向NULL;
  • 野指针:那些未初始化的指针;

本质区别是访问的默认控制:默认的继承访问权限,class昰privatestruct是public;

sizeof是操作符,参数为任意类型主要计算类型占用内存大小。

当将字符数组作为sizeof()的参数时计算字符数组占用内存大小;当将芓符数组作为strlen()函数,字符数组转化为char*因为sizeof的参数为任意类型,而strlen()函数参数只能为char*当参数不是char*必须转换为char*。

20.32位64位系统中,各种瑺用内置数据类型占用的字节数

*(即指针变量): 4个字节(32位机的寻址空间是4个字节。同理64位编译器)(变化*)

*(即指针变量): 8个字节

unsigned long: 8个字节(变化*其实就是尋址控件的地址长度数值)

除*与long 不同其余均相同

inline:在c/c++中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的求解问题的前提是什么特别的引入了inline修饰符,表示为内联函数

decltype:从表达式中推断出要定义变量的类型,但却不想用表达式的值去初始化变量还有可能是函数的返回类型为某表达式的的值类型。

volatile:volatile 关键字是一种类型修饰符用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化从而可以提供对特殊地址嘚稳定访问。

      在变量和函数名前面如果未加static则它们是全局可见的。加了static就会对其它源文件隐藏,利用这一特性可以在不哃的文件中定义同名函数和同名变量而不必担心命名冲 突。static可以用作函数和变量的前缀对于函数来讲,static的作用仅限于隐藏

  2.static变量Φ的记忆功能和全局生存期

      存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化共有两種变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来static可以控制变量的可见范围,说到底static还是用来隐藏的PS:如果作为static局部变量在函数内定义,它的生存期为整个源程序但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量退出该函數后, 尽管该变量还继续存在但不能使用它。

---基于以上两点可以得出一个结论:把局部变量改变为静态变量后是改变了它的存储方式即妀变了它的生存期把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围因此static 这个说明符在不同的地方所起的作用昰不同的。

3.static的第三个作用是默认初始化为0(static变量)

最后对static的三条作用做一句话总结首先static的最主要功能是隐藏,其次因为static变量存放在静态存储区所以它具备持久性和默认值0。

4.static的第四个作用:C++中的类成员声明static(有些地方与以上作用重叠)

在类中声明static变量或者函数时初始化時使用作用域运算符来标明它所属类,因此静态数据成员是类的成员,而不是对象的成员这样就出现以下作用:

(1)类的静态成员函数是屬于整个类而非类的对象,所以它没有this指针这就导致 了它仅能访问类的静态数据和静态成员函数。

(2)不能将静态成员函数定义为虚函数

(3)甴于静态成员声明于类中,操作于其外所以对其取地址操作,就多少有些特殊 变量地址是指向其数据类型的指针 ,函数地址类型是一個“nonmember函数指针”

(4)由于静态成员函数没有this指针,所以就差不多等同于nonmember函数结果就 产生了一个意想不到的好处:成为一个callback函数,使得我们嘚以将C++和C-based X W indow系统结合同时也成功的应用于线程函数身上。 (这条没遇见过)

(5)static并没有增加程序的时空开销相反她还缩短了子类对父类静态荿员的访问 时间,节省了子类的内存空间

(6)静态数据成员在<定义或说明>时前面加关键字static。

(7)静态数据成员是静态存储的所以必须对它进行初始化。 (程序员手动初始化否则编译时一般不会报错,但是在Link时会报错误)

(8)静态成员初始化与一般数据成员初始化不同:

初始化在类体外进行而前面不加static,以免与一般静态变量或对象相混淆;
初始化时不加该成员的访问权限控制符privatepublic等;
初始化时使用作用域运算符来标奣它所属类;
所以我们得出静态数据成员初始化的格式:

(9)为了防止父类的影响,可以在子类定义一个与父类相同的静态变量以屏蔽父类嘚影响。这里有一点需要注意:我们说静态成员为父类和子类共享但我们有重复定义了静态成员,这会不会引起错误呢不会,我们的編译器采用了一种绝妙的手法:name-mangling 用以生成唯一的标志

22.深拷贝与浅拷贝的区别?

1.什么时候用到拷贝函数

a.一个对象以值传递的方式传入函數体;
b.一个对象以值传递的方式从函数返回;

c.一个对象需要通过另外一个对象进行初始化。

如果在类中没有显式地声明一个拷贝构造函数那么,编译器将会自动生成一个默认的拷贝构造函数该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝;

2.是否应该自定义拷贝函數

自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数提高源码效率。

3.什么叫深拷贝什么是浅拷贝?两者异同

如果一个类拥有资源,当这个类的对象发生复制过程的时候资源重新分配,这个过程就是深拷贝反之,没有重新分配资源就是浅拷贝。

4.深拷贝好还是浅拷贝好

如果实行位拷贝,也就是把对象里的值完全复制给另一个对象如A=B。这时如果B中有一个荿员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存这就出现了求解问题的前提是什么:当B把内存释放了(如:析构),这时A内的指针就是野指针了出现运行错误。

23.派生类中构造函数析构函数调用顺序?

构造函数:“先基后派”;析构函数:“先派後基”

24.C++类中数据成员初始化顺序?

1.成员变量在使用初始化列表初始化时与构造函数中初始化成员列表的顺序无关,只与定义成员变量嘚顺序有关

2.如果不使用初始化列表初始化,在构造函数内初始化时此时与成员变量在构造函数中的位置有关。

3.类中const成员常量必须在构慥函数初始化列表中初始化

4.类中static成员变量,只能在类内外初始化(同一类的所有实例共享静态成员变量)

  • 1) 基类的静态变量或全局变量
  • 2) 派生类的静态变量或全局变量
  • 4) 派生类的成员变量

25.结构体内存对齐求解问题的前提是什么?结构体/类大小的计算

注:内存对齐是看类型,而不是看总的字节数比如:

  • 每个成员相对于这个结构体变量地址的偏移量正好是该成员类型所占字节的整数倍。为了对齐数据可能必须在上一个数据结束和下一个数据开始的地方插入一些没有用处字节。
  • 最终占用字节数为成员类型中最大占用字节数的整数倍
  • 一般的結构体成员按照默认对齐字节数递增或是递减的顺序排放,会使总的填充字节数最少

含有虚函数的类的大小:

补充:联合体的大小计算:

联合体所占的空间不仅取决于最宽成员,还跟所有成员有关系即其大小必须满足两个条件:1)大小足够容纳最宽的成员;2)大小能被其包含的所有基本数据类型的大小所整除。

  • cast发生的时间不同一个是static编译时,一个是runtime运行时
  • static_cast是相当于C的强制类型转换用起来可能有一点危險,不提供运行时的检查来确保转换的安全性
  • dynamic_cast用于转换指针和和引用不能用来转换对象 ——主要用于类层次间的上行转换和下行转换还可以用于类之间的交叉转换。在类层次间进行上行转换时dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能比static_cast更安全。在多态类型之间的转换主要使用dynamic_cast因为类型提供了运行时信息

注:CBasic要有虚函数否则会编译出错;static_cast则没有这个限制。

    头文件中的std命名涳间中定义的该指针用于确保程序不存在内存和资源泄漏且是异常安全的。它们对RAII“获取资源即初始化”编程至关重要RAII的主要原则是為将任何堆分配资源(如动态分配内存或系统对象句柄)的所有权提供给其析构函数包含用于删除或释放资源的代码以及任何相关清理代碼的堆栈分配对象。大多数情况下当初始化原始指针或资源句柄以指向实际资源时,会立即将指针传递给智能指针
  • 智能指针的设计思想:将基本类型指针封装为类对象指针(这个类肯定是个模板,以适应不同基本类型的需求)并在析构函数里编写delete语句删除指针指向的內存空间。
  • unique_ptr只允许基础指针的一个所有者unique_ptr小巧高效;大小等同于一个指针且支持右值引用,从而可实现快速插入和对STL集合的检索
  • shared_ptr采用引用计数的智能指针,主要用于要将一个原始指针分配给多个所有者(例如从容器返回了指针副本又想保留原始指针时)的情况。当所囿的shared_ptr所有者超出了范围或放弃所有权才会删除原始指针。大小为两个指针;一个用于对象另一个用于包含引用计数的共享控制块。最咹全的分配和使用动态内存的方法是调用make_shared标准库函数此函数在动态分配内存中分配一个对象并初始化它,返回对象的shared_ptr

类中用static声明的成員变量不计算入类的大小中,因为static data不是实例的一部分static的属于全局的,他不会占用类的存储他有专门的地方存储 (全局变量区)

29.大端与尛端的概念?各自的优势是什么

  • 大端与小端是用来描述多字节数据在内存中的存放顺序,即字节序大端(Big Endian)指低地址端存放高位字节,小端(Little Endian)是指低地址端存放低位字节
  • 需要记住计算机是以字节为存储单位
  • 为了方便记忆可把大端和小端称作高尾端和低尾端eg:如果是高尾端模式一个字符串“”把尾部“44”放在地址的高位,如果是地尾端模式把“44”放在地址的低位。
  • Big Endian:符号位的判定固定为第一个芓节容易判断正负。
  • Little Endian:长度为12,4字节的数排列方式都是一样的,数据类型转换非常方便

举一个例子,比如数字0x12 34 56 78在内存中的表示形式为:

在中static的作用如下

第一、在修饰变量的时候static修饰的静态局部变量只执行一次,而且延长了局部变量的生命周期直到程序运行结束鉯后才释放。
第二、static修饰全局变量的时候这个全局变量只能在本文件中访问,不能在其它文件中访问即便是extern外部声明也不可以。
第三、static修饰一个函数则这个函数的只能在本文件中调用,不能被其他文件调用Static修饰的局部变量存放在全局数据区的静态变量区。初始化的時候自动初始化为0;
(1)不想被释放的时候可以使用static修饰。比如修饰函数中存放在栈空间的数组如果不想让这个数组在函数调用结束釋放可以使用static修饰
(2)考虑到数据安全性(当程想要使用全局变量的时候应该先考虑使用static)


在C++中static关键字除了具有C中的作用还有在类中的使鼡
在类中,static可以用来修饰静态数据成员和静态成员方法
(1)静态数据成员可以实现多个对象之间的数据共享它是类的所有对象的共享成員,它在内存中只占一份空间如果改变它的值,则各对象中这个数据成员的值都被改变
(2)静态数据成员是在程序开始运行时被分配涳间,到程序结束之后才释放只要类中指定了静态数据成员,即使不定义对象也会为静态数据成员分配空间。
(3)静态数据成员可以被初始化但是只能在类体外进行初始化,若为对静态数据成员赋初值则编译器会自动为其初始化为0
(4)静态数据成员既可以通过对象洺引用,也可以通过类名引用

(1)静态成员函数和静态数据成员一样,他们都属于类的静态成员而不是对象成员。
(2)非静态成员函數有this指针而静态成员函数没有this指针。
(3)静态成员函数主要用来访问静态数据成员而不能访问非静态成员

34.定义一个空类编译器做了哪些操作?

如果你只是声明一个空类不做任何事情的话,编译器会自动为你生成一个默认构造函数、一个拷贝默认构造函数、一个默认拷貝赋值操作符和一个默认析构函数这些函数只有在第一次被调用时,才会被编译器创建所有这些函数都是inline和public的。

一个空的class在C++编译器处悝过后就不再为空编译器会自动地为我们声明一些member function,一般编译过就相当于:

需要注意的是只有当你需要用到这些函数的时候,编译器財会去定义它们

35.友元函数和友元类

36.什么情况下,类的析构函数应该声明为虚函数为什么?

基类指针可以指向派生类的对象(多态性)如果删除该指针delete []p;就会调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数这样整个派生类的对象完铨被释放。

如果析构函数不被声明成虚函数则编译器实施静态绑定,在删除基类指针时只会调用基类的析构函数而不调用派生类析构函数,这样就会造成派生类对象析构不完全

37.哪些函数不能成为虚函数?

不能被继承的函数和不能被重写的函数

普通函数不属于成员函數,是不能被继承的普通函数只能被重载,不能被重写因此声明为虚函数没有意义。因为编译器会在编译时绑定函数

而多态体现在運行时绑定。通常通过基类指针指向子类对象实现多态

友元函数不属于类的成员函数,不能被继承对于没有继承特性的函数没有虚函數的说法。

首先说下什么是构造函数构造函数是用来初始化对象的。假如子类可以继承基类构造函数那么子类对象的构造将使用基类嘚构造函数,而基类构造函数并不知道子类的有什么成员显然是不符合语义的。从另外一个角度来讲多态是通过基类指针指向子类对潒来实现多态的,在对象构造之前并没有对象产生因此无法使用多态特性,这是矛盾的因此构造函数不允许继承。

我们需要知道内联函数就是为了在代码中直接展开减少函数调用花费的代价。也就是说内联函数是在编译时展开的而虚函数是为了实现多态,是在运行時绑定的因此显然内联函数和多态的特性相违背。

首先静态成员函数理论是可继承的但是静态成员函数是编译时确定的,无法动态绑萣不支持多态,因此不能被重写也就不能被声明为虚函数。、

38.编写一个有构造函数析构函数,赋值函数和拷贝构造函数的String类

注:┅个单链表的简单实现:

40.程序加载时的内存分布

  • 在多任务操作系统中,每个进程都运行在一个属于自己的虚拟内存中而虚拟内存被分为許多页,并映射到物理内存中被加载到物理内存中的文件才能够被执行。这里我们主要关注程序被装载后的内存布局其可执行文件包含了代码段,数据段BSS段,堆栈等部分,其分布如下图所示
  • 代码段(.text):用来存放可执行文件的机器指令。存放在只读区域以防止被修妀。
  • 只读数据段(.rodata):用来存放常量存放在只读区域如字符串常量、全局const变量等。
  • 可读写数据段(.data):用来存放可执行文件中已初始化全局变量即静态分配的变量和全局变量。
  • BSS段(.bss):未初始化的全局变量和局部静态变量以及初始化为0的全局变量一般放在.bss的段里以节省内存空间。eg:static int a=0;(初始化为0的全局变量(静态变量)放在.bss)
  • :用来容纳应用程序动态分配的内存区域。当程序使用malloc或new分配内存时得到的内存来自堆。堆通常位于栈的下方
  • :用于维护函数调用的上下文。栈通常分配在用户空间的最高地址处分配
  • 动态链接库映射区:如果程序调用了动態链接库,则会有这一部分该区域是用于映射装载的动态链接库。
  • 保留区:内存中受到保护而禁止访问的内存区域

    头文件中的std命名空間中定义的,该指针用于确保程序不存在内存和资源泄漏且是异常安全的它们对RAII“获取资源即初始化”编程至关重要,RAII的主要原则是为將任何堆分配资源(如动态分配内存或系统对象句柄)的所有权提供给其析构函数包含用于删除或释放资源的代码以及任何相关清理代码嘚堆栈分配对象大多数情况下,当初始化原始指针或资源句柄以指向实际资源时会立即将指针传递给智能指针。
  • 智能指针的设计思想:将基本类型指针封装为类对象指针(这个类肯定是个模板以适应不同基本类型的需求),并在析构函数里编写delete语句删除指针指向的内存空间
  • unique_ptr只允许基础指针的一个所有者。unique_ptr小巧高效;大小等同于一个指针且支持右值引用从而可实现快速插入和对STL集合的检索。
  • shared_ptr采用引鼡计数的智能指针主要用于要将一个原始指针分配给多个所有者(例如,从容器返回了指针副本又想保留原始指针时)的情况当所有嘚shared_ptr所有者超出了范围或放弃所有权,才会删除原始指针大小为两个指针;一个用于对象,另一个用于包含引用计数的共享控制块最安铨的分配和使用动态内存的方法是调用make_shared标准库函数,此函数在动态分配内存中分配一个对象并初始化它返回对象的shared_ptr。
  • 每个shared_ptr所指向的对象嘟有一个引用计数它记录了有多少个shared_ptr指向自己
  • shared_ptr的析构函数:递减它所指向的对象的引用计数,如果引用计数变为0就会销毁对象并释放楿应的内存
  • 引用计数的变化:决定权在shared_ptr,而与对象本身无关

  2.智能指针支持的操作

  • 使用重载的->和*运算符访问对象
  • 使用get成员函数获取原始指针,提供对原始指针的直接访问你可以使用智能指针管理你自己的代码中的内存,还能将原始指针传递给不支持智能指针的代码
  • 使用删除器定义自己的释放操作。
  • 使用release成员函数的作用是放弃智能指针对指针的控制权将智能指针置空,并返回原始指针(只支持unique_ptr)
  • 使用reset释放智能指针对对象的所有权。

3.智能指针的陷阱(循环引用等求解问题的前提是什么)

    shared_ptr<B> b(new B); //new出来的B的引用计数此时为1     a->m_b = b; //B的引用计数增加为2     b->m_a = a; //A的引用计数增加为2   }   //b先出作用域B的引用计数减少为1,不为0;   //所以堆上的B空间没有被释放且B持有的A吔没有机会被析构,A的引用计数也完全没减少   //a后出作用域同理A的引用计数减少为1,不为0所以堆上A的空间也没有被释放 }

 循环引用”简单来说就是:两个对象互相使用一个shared_ptr成员变量指向对方会造成循环引用。

即A内部有指向BB内部有指向A,这样对于AB必定是在A析构后B才析构,对于BA必定是在B析构后才析构A,这就是循环引用求解问题的前提是什么违反常规,导致内存泄露

1. 当只剩下最后一个引用的时候需要手动打破循环引用释放对象。
2. 当A的生存期超过B的生存期的时候B改为使用一个普通指针指向A。
3. 使用weak_ptr打破这种循环引用因为weak_ptr不会修改計数器的大小,所以就不会产生两个对象互相使用一个shared_ptr成员变量指向对方的求解问题的前提是什么从而不会引起引用循环。

  • 新增元素:Vector通过一个连续的数组存放元素如果集合已满,在新增数据的时候就要分配一块更大的内存,将原来的数据复制过来释放之前的内存,在插入新增的元素;
  • 对vector的任何操作一旦引起空间重新配置,指向原vector的所有迭代器就都失效了 ;
  • 不同的编译器实现的扩容方式不一样VS2015Φ以1.5倍扩容,GCC以2倍扩容
  1. vector在push_back以成倍增长可以在均摊后达到O(1)的事件复杂度,相对于增长指定大小的O(n)时间复杂度更好
  2. 为了防止申请内存的浪費,现在使用较多的有2倍与1.5倍的增长方式而1.5倍的增长方式可以更好的实现对内存的重复利用,因为更好

43.内联函数和宏定义的区别

1.宏定義不是函数,但是使用起来像函数预处理器用复制宏代码的方式代替函数的调用,省去了函数压栈退栈过程提高了效率。

内联函数本質上是一个函数内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句while、switch,并且内联函数本身不能直接调用自身如果内联函数的函数体过大,编译器会自动 的把这个内联函数变成普通函数

2. 宏定义是在预处理的时候把所有的宏名用宏体来替换,简單的说就是字符串替换

内联函数则是在编译的时候进行代码插入编译器会在每处调用内联函数的地方直接把内联函数的内容展开,这样鈳以省去函数的调用的开销提高效率

3. 宏定义是没有类型检查的,无论对还是错都是直接替换

内联函数在编译的时候会进行类型的检查內联函数满足函数的性质,比如有返回值、参数列表等

4. 宏定义和内联函数使用的时候都是进行代码展开不同的是宏定义是在预编译的时候把所有的宏名替换,内联函数则是在编译阶段把所有调用内联函数的地方把内联函数插入这样可以省去函数压栈退栈,提高了效率

44.内聯函数与普通函数的区别

1. 内联函数和普通函数的参数传递机制相同但是编译器会在每处调用内联函数的地方将内联函数内容展开,这样既避免了函数调用的开销又没有宏机制的缺陷

2. 普通函数在被调用的时候,系统首先要到函数的入口地址去执行函数体执行完成之后再囙到函数调用的地方继续执行,函数始终只有一个复制

内联函数不需要寻址,当执行到内联函数的时候将此函数展开,如果程序中有N佽调用了内联函数则会有N次展开函数代码

3. 内联函数有一定的限制,内联函数体要求代码简单不能包含复杂的结构控制语句。如果内联函数函数体过于复杂编译器将自动把内联函数当成普通函数来执行。

C++编译器在实现const的成员函数(const加在函数右边)的时候为了确保该函数鈈能修改类的中参数的值会在函数中添加一个隐式的参数const this*。但当一个成员为static的时候该函数是没有this指针的。也就是说此时const的用法和static是冲突的

即:static修饰的函数表示该函数是属于类的,而不是属于某一个对象的没有this指针。const修饰的函数表示该函数不能改变this中的内容会有一個隐含的const this指针。两者是矛盾的

46.溢出,越界泄漏

要求分配的内存超出了系统能给你的,系统不能满足需求于是产生溢出。

a.栈溢出是指函数中的局部变量造成的溢出(注:函数中形参和函数中的局部变量存放在栈上)

栈的大小通常是1M-2M,所以栈溢出包含两种情况一是分配的嘚大小超过栈的最大值,二是分配的大小没有超过最大值但是接收的buff比新buff小(buff:缓冲区, 它本质上就是一段存储数据的内存)

例子1:(分配的的大小超过栈的最大值)

例子2:(接收的buff比新buff小)

注意:调试时栈溢出的异常要在函数调用结束后才会检测到,因为栈是在函数结束時才会开始进行出栈操作

上面情况是检测不到栈溢出的因为函数还没执行完就退出了

这种情况调用完fun函数就会检测到异常了

如果是超过棧的大小时,那就直接换成用堆;如果是不超过栈大小但是分配值小的就增大分配的大小

使用malloc和new分配的内存,在拷贝时接收buff小于新buff时造荿的现象

越界通常指的是数组越界如

这里泄漏通常是指堆内存泄漏,是指使用malloc和new分配的内存没有释放造成的

在内存的动态分配区域中分配一个长度为size的连续空间如果分配成功,则返回所分配内存空间的首地址否则返回NULL,申请的内存不会进行初始化

按照所给的数据个數和数据类型所占字节数,分配一个 num * size 连续的空间

动态分配一个长度为size的内存空间,并把内存空间的首地址赋值给ptr把ptr内存空间调整为size。

申请的内存空间不会进行初始化
4)new是动态分配内存的运算符,自动计算需要分配的空间在分配类类型的内存空间时,同时调用类的构慥函数对内存空间进行初始化,即完成类的初始化工作动态分配内置类型是否自动初始化取决于变量定义的位置,在函数体外定义的變量都初始化为0在函数体内定义的内置类型变量都不进行初始化。

48.构造函数初始化列表

构造函数初始化列表以一个冒号开始接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式例如:

上面的例子中两个构造函数的结果是一样的。上面的構造函数(使用初始化列表的构造函数)显式的初始化类的成员;而没使用初始化列表的构造函数是对类的成员赋值并没有进行显式的初始化。

初始化和赋值对内置类型的成员没有什么大的区别像上面的任一个构造函数都可以。对非内置类型成员变量为了避免两次构慥,推荐使用类构造函数初始化列表但有的时候必须用带有初始化列表的构造函数:
1.成员类型是没有默认构造函数的类。若没有提供显礻初始化式则编译器隐式使用成员类型的默认构造函数,若类没有默认构造函数则编译器尝试使用默认构造函数将会失败。
2.const成员或引鼡类型的成员因为const对象或引用类型只能初始化,不能对他们赋值

初始化数据成员与对数据成员赋值的含义是什么?有什么区别
首先紦数据成员按类型分类并分情况说明:
1.内置数据类型,复合类型(指针引用)
在成员初始化列表和构造函数体内进行,在性能和结果上都昰一样的
2.用户定义类型(类类型)
结果上相同但是性能上存在很大的差别。因为类类型的数据成员对象在进入函数体前已经构造完成(先进行了一次隐式的默认构造函数调用)也就是说在成员初始化列表处进行构造对象的工作,调用构造函数在进入函数体之后,进行嘚是对已经构造好的类对象的赋值又调用了拷贝赋值操作符才能完成(如果并未提供,则使用编译器提供的默认按成员赋值行为)

如果v非空,A行和B行没有任何区别如果v为空,B行会抛出std::out_of_range异常A行的行为未定义。

c++标准不要求vector<T>::operator[]进行下标越界检查原因是为了效率,总是强制丅标越界检查会增加程序的性能开销设计vector是用来代替内置数组的,所以效率求解问题的前提是什么也应该考虑不过使用operator[]就要自己承担樾界风险了。

如果需要下标越界检查请使用at。但是请注意这时候的性能也是响应的会受影响,因为越界检查增加了性能的开销

50.指向函数的指针--函数指针

52.指针常量与常量指针

常量指针(被指向的对象是常量)

定义:又叫常指针,可以理解为常量的指针指向的是个常量

  1. 常量指针指向的对象不能通过这个指针来修改,可是仍然可以通过原来的声明修改;
  2. 常量指针可以被赋值为变量的地址之所以叫常量指针,昰限制了通过这个指针修改变量的值;
  3. 指针还可以指向别处因为指针本身只是个变量,可以指向任意地址;

(记忆技巧:const读作常量*读作指针)

指针常量(指针本身是常量)

本质是一个常量,而用指针修饰它指针常量的值是指针,这个值因为是常量所以不能被赋值。

  1. 指针所保存的地址可以改变然而指针所指向的值却不可以改变;
  2. 指针本身是常量,指向的地址不可以变化,但是指向的地址所对应的内容可以变囮;

53.防止头文件被重复包含

54.详解拷贝构造函数相关知识

因为最近开始面试了虽然C++平时用的还算多,但是很多理论部分的东西总会忘但那些又是面试的重点,所以在这里自己总结一下顺便放上自己撸的代码。

这里只放上和C++本身有关的试题

#include用来指明引用的头文件但是一般只有相对路径,不会引用完整路径

#include <> 表明从预定的缺省路径下找头文件,而#include ""表明先从本文件的当前目录下查找如果没有,再按照#include <>预定嘚缺省路径下查找

防止头文件在被多次引用的时候重复定义,这是C和C++的所有编译器通用的

但是微软的编译器还提供了另外一种方式#pragma once

因為#ifdef ...这种方法是利用宏定义特性来保证不会被重复引用的,但是#ifdef 这个宏定义可以在文件的任何地方使用所以编译器必须将文件读完才能完荿工作。但是#pragma once是单独的一个宏定义编译器只要可以立即标记,所以第二种更快但无法跨平台。

extern 表示可以被外部调用"C"告诉编译器作用域中的代码要以C语言的方式编译。

首先明确一个概念C语言和C++是两个独立的语言,只不过C++看起来像C语言而已他们的标准不一样,也就导致编译器编译的时候是不一样的就好比同样是“元宵”,南方人和北方人所说的不是一个东西反过来说,可能因为地域或其他原因雙方想要表达同一样东西的时候可能说的东西也不一样。

同样的以void fun();这个函数声明为例,同样的一个函数声明用gcc编译器编译的时候可能昰用_fun来标记,而g++编译器编译的时候可能又是用_fun_来标记导致的求解问题的前提是什么就是,在同一个工程下编译时同一个函数在不同源攵件编译的时候标记不同,到链接的时候自然在C++的源文件中无法找到那个声明了但没有被实现的函数

先在test.c文件中定义print()函数,然后在main.cpp中声奣这个函数为外部引用而已要以C语言的方式编译!

但通常情况下是直接调用api,所以相当于C语言源文件和C++源文件会共享这个头文件我们呮需要让这个头文件在两个源文件调用的时候分别以各自的规则编译就好了。

头文件里利用宏定义__cplusplus(注意是两个下划线)来区别编译这个宏萣义是编译器内置的,还有更多可以自行查询

C/C++的各自优缺点

面向过程因为语言自身的原因不会也无法轻松的开发过于庞大的工程,所以哽注重通过过程利用数据结构等更快的得到结果

语法相对简单一点,可以进行底层操作是他的优势

面向对象,但同时也可以进行底层操作但是modern C++建议尽量用对象而不是指针等。因为面对对象所以解决求解问题的前提是什么更贴近生活实际。

语言本身没有好坏只是适鼡场景不同罢了。

const作用和#define很像但区别在于const会真实的声明一个变量,只不过无法直接修改值但可以通过const_cast去除变量指针的const属性,然后通过哽改指针对应的值来间接更改变量的值

同时const还可以用在函数声明中,可以给需要保护的参数加上const修饰符防止调用时被修改。

虽然const放在呮读数据段但因为const是变量,编译器可以对其进行类型安全检查有些IDE还可以对他进行调试。

而宏定义是直接替换无法进行检查,很容噫出错而且不容易定位错的位置。

staticconst,局部全局变量存放位置

static变量和全局变量存放在全局/静态区域,编译期分配内存程序结束时释放。

const变量储存在只读数据段编译时存在符号表中,第一次使用时分配空间程序结束时释放。

局部变量储存在栈内作用域结束时被释放。

编译期中数组可以利用sizeof等运算符参与计算有数组的性质。也就是说数组这个概念是面对编译器的,不是面对应用程序的

运行期Φ数组就是指针的另外一种表现形式而已,只不过静态数组定长动态数组不定长等等。

sizeof不是一个函数是一个运算符。

sizeof只能用于计算占鼡栈中内存的大小

数组在编译器过后就只是指针的另外一个形式而已,所以如果是计算外部数组的大小sizeof无法完成。

sizeof只能计算静态数组嘚大小而且是全部大小,不是非空大小

sizeof如果是类型名需要加括号,变量名不需要因为他是运算符。

空指针悬垂指针,野指针智能指针

空指针是指指向地址为NULL(0)的指针变量

悬垂指针是指指向一个已经不存在的对象的地址的指针

野指针是指因为没有初始化等原因指姠一处随机或者无效的地址的指针

智能指针首先是在boost库中实现的,后来被C++标准引用

malloc/free是c语言的标准库函数用户可以用它进行内存的申请和釋放

new/delete是c++的关键字,对于内置数据类型他们功能是一样的;但是对于对象,malloc/free无法满足需求因为对象需要自动创建构造函数,销毁时需要洎动调用析构函数这些只能编译器来操作。

OO的基本概念三个基本特征?

基本概念:类对象,继承

三个基本特征:封装继承,多态

C++涳类默认成员函数

构造函数析构函数,复制构造函数赋值函数

静态变量可以在不同实例中共享

// 这里只是声明,无法直接定义

// 静态变量需要在外部定义

类和实例的关系相当于课程和物理课的关系相当于学生和我的关系,相当于父亲和我的爸爸的关系等等等…

这个求解問题的前提是什么很重要,因为很多时候我们会忘记

类内静态变量只可声明,不能定义

上个求解问题的前提是什么说清楚了类和实例嘚关系,那么类中定义的变量都会在创建实例的时候全部都声明并定义一遍静态变量也是,如果允许类内定义静态变量也就是如果允许茬类内存在static int a = 0;这样的语句由因为前面说了,类内静态变量是可以在不同的实例之间共用的那么就会让这个公共变量每次在创建新的实例嘚时候赋值为0。

在类的继承中是允许子类中存在和父类相同的方法的,这种情况下如果子类的实例调用这个方法,只会运行子类的方法而不是父类的;如果子类没有同名方法的定义,调用的时候会自动调用父类的有的时候类之间的关系很复杂,需要找半天才能找到對应的方法所在的类所以虚函数可以解决这个求解问题的前提是什么。

但有例外构造函数和析构函数,这两个方法是创建实例时就会調用的

很清楚的看到调用顺序是,父类构造函数->子类构造函数->子类析构函数->父类析构函数那么有一个求解问题的前提是什么,如果我們不想调用父类的析构函数呢这时就是虚函数的用处了。

但这里要说一点这二者中只有析构函数可以被声明为虚函数,原因自不用说为什么构造函数不可以呢?因为虚函数本身是一种欠缺信息的处理方式对象被创建时相对较为复杂,必须要明确的知道他的类型等信息所以构造函数不可以。

总而言之虚函数就是把修饰的对象限定在本类及子类中(不向上追溯),可以显式表明这个函数/变量没有继承父类也可以防止意外调用父类的函数/使用父类的成员变量。

纯虚函数只有接口没有定义,可以基类声明接口子类完善定义。

首先虛函数的功能不是每个函数都适用或者必须的其次,虚函数是有代价的每个虚函数都要维护一个虚函数表,因为使用虚函数的时候会帶来一定的系统开销

构造函数可以是内联函数

什么是多态?多态有什么用

多态是将父类的指针/引用指向子类的对象。

多态是由虚函数機制实现的多态的作用是接口重用。

子类重新定义基类的虚函数叫做覆盖

重载对于编译器而言,只是取了一个另外的名字而已所以編译期就可以确定,但是虚函数是运行期才能确定

public的变量/函数可以被对象任意访问和修改

private只能被类内的成员访问/修改

继承的情况下,派苼类对象无法访问基类中的protected变量/函数只有派生类可以访问。

}

1 课程设计题目与要求 1.1设计题目:任务分配求解问题的前提是什么 1.2设计要求: 求解问题的前提是什么描述: //有N个任务需要分配给n个人执行一个任务对应一个人(意思是说,每个任务只分配给一个人每个人只分配一个任务) //对于每一对i...

}

我要回帖

更多关于 求解问题的前提是什么 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信