| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> C++++ -> 正文阅读 |
|
[C++知识库]C++++ |
目录
C++和Java的区别语言特性
垃圾回收
应用场景
C++和Python的区别
c和c++区别
cout和printf有什么区别?
flush立即强迫缓冲输出。 printf是无缓冲输出。有输出时立即输出 程序在执行int main(int argc, char *argv[])时的内存结构,你了解吗?参数的含义是程序在命令行下运行的时候,需要输入argc 个参数,每个参数是以char 类型输入的,依次存在数组里面,数组是 argv[],所有的参数在指针char * 指向的内存中,数组的中元素的个数为 argc 个,第一个参数为程序的名称。 C++三大特性封装 保持原有类特性的基础上进行扩展,派生类从基类获取方法(函数)和属性(成员变量)的过程。(如果类 B 继承于类 A,那么 B 就拥有 A 的方法和属性) 实现方式有两类: 实现继承: 实现继承是指直接使?基类的属性和?法??需额外编码的能?。 接?继承:接?继承是指仅使?属性和?法的名称、但是?类必需提供实现的能?。 例子:将人定义为一个抽象类,拥有姓名、性别、年龄等公共属性,吃饭、睡觉、走路等公共方法,在定义一个具体的人时,就可以继承这个抽象类,既保留了公共属性和方法,也可以在此基础上扩展跳舞、唱歌等特有方法。 接口的多种不同实现方式即为多态。(同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果)(允许将子类类型的指针赋值给父类类型的指针) 例子: 静态多态: 优点: 1)大大提高了代码的可复用性;2)提高了了代码的可维护性,可扩充性; C++的异常处理的方法try、throw和catch关键字
形参与实参的区别
静态类型和动态类型,静态绑定和动态绑定的介绍
静态函数和虚函数的区别静态函数是在编译时就已经确定好了运行的时机,而虚函数是使用动态绑定,虚函数使用了虚函数表机制,调用会增加一次的内存开销。 虚函数表具体怎样实现运行时多态所谓虚函数表是一个类的虚函数地址表,在每个对象创建的时候,都会有一个vptr指向虚函数表,当继承它的子类对虚函数进行重写时,虚函数表中的对应函数地址将被新地址覆盖,所以当父类指针调用子类的成员函数时,虚函数指针就可以指向对应的函数。 当调用虚函数时过程如下(引自More Effective C++):
public,protected,private
全局变量和局部变量有什么区别?
类的成员函数(1)拷贝函数 类成员初始化方式?构造函数的执行顺序 ?为什么用成员初始化列表会快一些?
当C++定义类时,编译器会为类自动生成哪些函数?这些函数各自都有什么特点?
注意: 唯有当这些函数被需要(被调用)时,它们才会被编译器创建出来。但是这些函数一般都会被使用到。 什么是虚函数,为什么析构函数必须是虚函数,为什么c++默认析构函数不是虚函数虚函数是在某个基类中声明,在其派生类中被重写的成员函数。用于实现多态性,简单来说就是,对于不同的类,相同的方法可以采用不同的策略。 如果析构函数不是虚函数,那么当一个派生类经由一个基类指针删除的时候,其结果是未定义的,实际实行的时候,通常是对象的派生类部分没有被销毁,而其中基类部分被销毁掉了,就产生了一种局部销毁的现象, 从而造成资源泄漏。 为了消除这个问题,就必须在基类中定义virtual的析构函数,从而销毁对象时,才能完整销毁。 将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。 C++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针,占用额外的内存。而对于不会被继承的类来说,其析构函数如果是虚函数,就会浪费内存。因此C++默认的析构函数不是虚函数,而是只有当需要当作父类时,设置为虚函数。 如何让一个类不能实例化?将类定义为抽象基类或者将构造函数声明为private。 staic(修饰的数据成员存储在全局数据区)(1)隐藏。 修饰全局变量时,表明一个全局变量只对定义在同一文件中的函数可见。 (静态函数/静态全局变量不能被其他文件所用;其他文件可以定义相同名字的函数,不会发生冲突) C++如何创建一个类,使得他只能在堆或者栈上创建?
析构函数能否抛出异常不能。
解决方法
内联函数 inline(1)目的:为了解决程序中函数调用的效率问题
inline跨文件使用内联函数必须在调用它的每个文件中定义, 若想在所有文件中使用,最好在头文件中定义,且一旦内联函数在多个头文件中定义,则会产生内联函数的重定义 常量指针和指针常量常量指针:指向常量的指针,(地址可变,内容不变),也是底层const(对象(指针、引用等)指向的是一个常量)
指针常量:表示指针是一个常量,(地址不变,内容可变)无法改变其指向的内存空间。顶层const(指对象本身就是一个常量)
左值和右值左右值引用左值是对应内存中有确定存储地址的对象的表达式的值 std::move
指针和引用(1)引用必须被初始化(引用类型的初始值必须是一个对象),指针不必(但最好要初始化)。 (2)引用无法更改为另一个对象的引用,而指针可以任意改变指向的对象。 (3)不存在指向空值的引用,但是存在指向空值的指针。 (4)指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。 (5)指针是一个对象,可以定义指向指针的指针。但引用不是对象,没有实际地址,所以不能定义指向引用的指针,也不能定义指向引用的引用。 (7)对与,sizeof取大小,指针固定为4,引用是对象的大小 相同点: (2)指针指向一块内存,它的内容是所指内存的地址; (3)引用是某块内存的别名。 普通指针(1)忘记释放资源,导致资源泄露(常发生内存泄漏问题) 野指针和悬空指针都是是指向无效内存区域(这里的无效指的是"不安全不可控")的指针,访问行为将会导致未定义行为。 野指针 : 指的是没有被初始化过的指针
悬空指针: 指针最初指向的内存已经被释放了的一种指针。
此时 p和p2就是悬空指针,指向的内存已经被释放。继续使用这两个指针,行为不可预料。需要设置为p=p2=nullptr 。此时再使用,编译器会直接保错。 避免野指针比较简单,但悬空指针比较麻烦。c++引入了智能指针,C++智能指针的本质就是避免悬空指针的产生。 产生原因及解决办法: **野指针:**指针变量未及时初始化 => 定义指针变量及时初始化,要么置空。 c++的三种智能指针c++11标准引入了三种智能指针,均定义在头文件下,其本质上是一个模板类,拥有构造函数和析构函数,在超出其作用域后,它会主动释放其管理的内存。 shared_ptr是一种共享式指针,采用引用计数,指针之间共享内存,传递一次引用就加1,引用数为0时自动销毁内存。shared_ptr可以使用方法 unique_ptr 为了保证同一时间仅能有一个指针来管理一块内存,c++11引入了unique_ptr,它是一种独占式指针,仅支持一个指针指向该内存。可以使用 weak_ptr 当有两个shared_ptr相互指向发生循环引用时,会产生死锁导致内存泄漏,因此c++11为了防止死锁现象的发生,引入了弱引用的概念,它的存在不会改变内存的引用计数,仅仅用于辅助shared_ptr来管理内存,提供一个访问内存的方式,可用于核查指针类,即检查该对象是否已经被释放。 函数指针和指针函数函数指针 指向函数的指针变量。函数指针本身首先是一个指针变量,该指针变量指向一个具体的函数, 这正如用指针变量可指向整形变量, 字符型, 数组一样,这里是指向函数。 用途: int (*f)(int a, int b); // 声明函数指针 指针函数 一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。
C++中关于变量的存储位置BSS段 :通常是指用来存放程序中 未初始化的全局变量、静态变量(全局变量未初始化时默认为0)的一块内存区域 数据段 :通常是指用来存放程序中 初始化后的全局变量和静态变量 代码段 :通常是指用来存放程序中 代码和常量 堆 :通常是指用来存放程序中 进程运行时被动态分配的内存段 ( 动态分配:malloc / new,者动态释放:free / delete) 栈 :通常是指用来存放程序中 用户临时创建的局部变量、函数形参、数组(局部变量未初始化则默认为垃圾值)也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量) 堆(heap)和栈(stack)的区别如何让一个函数在main函数执行前先执行C++的四种强制转换reinterpret_cast/const_cast/static_cast /dynamic_cast隐式类型转换概念: 对于内置类型,当运算符两端类型不同时,编译器会自动使低精度的类型向高精度类型转换。 在类的构造函数中,可以直接传入参数,编译器会为其生成一个临时对象用于构造。 new/delete与malloc/free的区别new和delete是c++的关键字,而malloc和free是内置函数,当使用new对对象进行分配空间时,编译器会自动得到该对象的大小,但是malloc需要显式给出需要分配的空间大小。 对于自定义的类来说,new会先调用operator new申请足够的空间,然后调用类类型的构造函数,最后返回该类型的指针,delete会先调用类的析构函数,然后调用operator delete释放内存空间。而malloc和free是内置函数,无法要求他们调用构造函数和析构函数。 内存分配方式内存分配方式有三种: [1]从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在 [2]在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理 [3]从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。 c++内存管理c++中内存分为五个区域
C如何进行函数调用对于每个函数,c++都会为它分配一个栈,在进行函数调用之前,先将当前指令的esp指针压入栈中,并将参数入栈,跳转到函数存储的地址,函数执行结束后,恢复esp指针,回到原地址继续运行。 拷贝构造函数的调用时机1.直接初始化和拷贝初始化时 2.将一个对象作为实参传递给一个非引用或非指针类型的形参时 3.从一个返回类型为非引用或非指针的函数返回一个对象时 4.用花括号列表初始化一个数组的元素或者一个聚合类(很少使用)中的成员时。 STL由什么组成容器:容纳,包含一种元素或元素集合。 迭代器: 用于遍历,访问容器中的元素,一般作为泛型算法的参数。 仿函数: 泛型算法:用来操作容器中元素的方法。 分配器:为容器等分配空间。 配接器:将一个class的接口转换为另一个class的接口,使原本因接口不兼容不能合作的两个class共同运作。 map 和set的区别,它们是如何实现的map和set都是c++的关联容器,其底层实现都是红黑树,他们所有的接口都由红黑树给出,所以几乎所有的操作行为都是转调红黑树的操作。 区别: map是映射,其中的元素是key-value的,可以按key值来索引value值。 set是集合,其中元素只是一个值,仅包含一个关键字。 set的迭代器是const的,它不支持使用迭代器修改元素,而map允许修改value的值,他们的元素都是根据关键字来保证有序的,所以不能轻易修改,只能将原关键字删除,重新插入,但是对于这些操作都是O(logn)的,所以时间开销较大。 另外,map支持下标操作,set不支持。 vector 和list的区别,它们是如何实现的vector和list都是c++中的容器,vector是向量,底层存储空间是连续的,也就是数组,所以对于随机读取修改所需时间较低,为O(1),但插入的复杂度较低,每次插入要将其后面的元素向后移动,所以最坏时间复杂度是O(n)的。且在可分配空间不足时,可能需要将所有的数据移动到另一块内存。 list底层实现是双向链表,底层存储时非连续的,随机读取只能从头节点向后查找,所以最坏时间复杂度是O(n)的,但插入仅需 O(1)。 有哪些内存泄漏?如何判断内存泄漏?如何定位内存泄漏?内存泄漏是指堆内存的泄露,堆内存在程序中由程序动态分配的内存,使用过后需要显示释放,有些时候忘记释放已使用完的内存,就会发生内存泄漏。若运行过久,可能会导致栈溢出致使程序崩溃。
检测工具
动态链接和静态链接的区别
allocator和new区别allocator: new分配的空间会造成空间的浪费,因为new分配的空间将内存分配和对象构造组合在一起,造成不必要的浪费。 一个allocator类调用allocate来分配空间,调用construct来构造对象,destroy来销毁对象。 STL迭代器删除元素对于顺序容器,当使用erase删除元素后,会导致排在后面的迭代器失效,每个元素向前移动一位,但是erase会指向下一个迭代器。 对于关联容器,由于底层总是树形结构或者哈希结构,对后面的迭代器是没有影响的。 resize和reserve的区别resize是对改变当前容器元素的数量,若resize大小小于当前容器元素的数量,则删除后面的元素。 reserve是改变其预留空间,保证内存空间可容纳的元素数量,并不生成新的对象,若参数小于当前容器元素数量,则不改变当前的元素数量。 c++内存对齐内存对齐就是计算机系统对数据存放位置的限制。内存是以字节为单位,但是大部分处理器并不是按字节块来存取内存的.它一般会以双字节,四字节,8字节,16字节甚至32字节为单位来存取内存,我们将上述这些存取单位称为内存存取粒度 大部分处理器的内存存取粒度是4字节8字节这样的,如果不进行内存对齐,可能会产生一个整数的存储位置被分到两块内存,需要cpu进行两次读取再拼接,需要做的工作十分复杂,而对齐后可以将一个数据一次直接读取出来,提高cpu的读取效率,一般编译器默认的内存对齐系数是4,在结构体或类中,内存对齐系数一般为其成员变量的最大内存对齐系数。 可以使用#pragma pack(n)来改变默认对齐系数 如何获得结构成员相对于结构开头的字节偏移量结构体的对齐,为什么要对齐内存对齐主要遵从以下三个原则
为什么需要对齐? 1.平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 说一下c++的编译过程
深拷贝与浅拷贝
深拷贝不仅拷贝值,还开辟出一块新的空间用来存放新的值,即使原先的对象被析构掉,释放内存了也不会影响到深拷贝得到的值。在自己实现拷贝赋值的时候,如果有指针变量的话是需要自己实现深拷贝的
浅拷贝只是拷贝一个指针,并没有新开辟一个地址,拷贝的指针和原来的指针指向同一块地址,如果原来的指针所指向的资源释放了,那么再释放浅拷贝的指针的资源就会出现错误。 当类成员存在指针时,若使用默认构造函数使用简单的浅拷贝,那么当使用析构函数释放资源时,会提前释放成员指针指向的数据,可能造成空悬指针多次释放导致内存泄漏。 零拷贝
工作原理 系统调用直接通过DMA将数据拷贝到内核缓冲区,然后被内核直接转发到与另一个文件相关的内核缓冲区,其中一直都是内核态,不需要进入用户态。 线程安全线程安全是指内存安全,也就是保证本线程所使用的数据,不被其他线程暗改,导致得到的数据不是自己想要的数据。 解决线程安全的办法
c++ 11/14/17新特性11:
14:
17:
什么是回调函数?为什么要使用回调函数?如何使用回调函数? |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 22:01:57- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |