C++:一些常见知识点的区别(整理)

struct与class的区别

  • C语言中struct与class的区别:struct只作为一种复杂数据类型定义的结构体,不能用于面向对象编程;C语言没有class关键字。
  • C++语言中struct与class的区别:对于成员访问权限以及继承方式,class默认都是private,struct默认是public;class可以用于表示模板类型,struct不行;一般来说,用到继承时常用class,没用到继承时则使用struct。

内存泄漏与内存溢出的区别

  • 内存溢出(out of memory):是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;例如申请了一个int型的地址空间,但给它存放了long型的数据,就会导致内存溢出。
  • 内存泄漏(memory leak):是指程序申请内存后,无法释放已申请的内存空间,内存泄漏多了会导致可用内存空间变小,进一步造成内存溢出。

堆和栈的区别

  • 管理方式:堆中资源由程序员控制(通过malloc/free、new/delete,容易产生memory leak),栈资源由编译器自动管理。
  • 系统响应:对于堆,系统有一个记录空闲内存地址的链表,当系统收到程序申请时,遍历该链表,寻找第一个大于所申请空间的空间的堆结点,删除空闲结点链表中的该结点,并将该结点空间分配给程序(大多数系统会在这块内存空间首地址记录本次分配的大小,这样delete才能正确释放本内存空间,另外,系统会将多余的部分重新放入空闲链表中)。对于栈,只要栈的剩余空间大于所申请空间,系统就会为程序分配内存,否则报异常出现栈空间溢出错误。
  • 空间大小:堆是不连续的内存区域(因为系统是用链表来存储空闲内存地址的,自然不是连续),堆的大小受限于计算机系统中有效的虚拟内存(32位机器上理论上是4G大小),所以堆的空间比较灵活,比较大。栈是一块连续的内存区域,大小是操作系统预定好的,windows下栈大小是2M(也有是1M,在编译时确定,VC中可设置)。
  • 碎片问题:对于堆,频繁的new/delete会造成大量内存碎片,降低程序效率。对于栈,它是一个先进后出(first-in-last-out)的结构,进出一一对应,不会产生碎片。
  • 生长方向:堆向上,向高地址方向增长;栈向下,向低地址方向增长。
  • 分配方式:堆是动态分配(没有静态分配的堆)。栈有静态分配和动态分配,静态分配由编译器完成(如函数局部变量),动态分配由alloca函数分配,但栈的动态分配资源由编译器自动释放,无需程序员实现。
  • 分配效率:堆由C/C++函数库提供,机制很复杂,因此堆的效率比栈低很多。栈是机器系统提供的数据结构,计算机在底层对栈提供支持,分配专门的寄存器存放栈地址,提供栈操作专门的指令。

指针与引用的区别

  • 指针是一个实体,有分配内存空间,引用只是一个别名,不分配内存空间
  • 指针不用但最好初始化,引用必须初始化
  • 引用只能初始化一次,指针可以多次赋值
  • 可以有const指针,但没有const引用,例如 int* const p合法,int& const p有些编译器会报错,有些编译器会警告并忽视该const修饰符
  • 指针可以指向空值,引用不能指向空值
  • “sizeof引用”得到的是变量对象的大小,“sizeof指针”得到的是指针本身的大小
  • 指针和引用的自增运算符意义不同
  • 指针可以有多级,引用只能是一级

五种内存分配区域

  • C/C++编译的程序所占用内存区域一般分为以下5个部分:

    • 栈区(stack):由编译器自动分配和释放,用来存放函数的参数、局部变量等。其操作方式类似于数据结构中的栈。
    • 堆区(heap):一般由程序员分配和释放(通过malloc/free、new/delete),若程序员没有释放,则程序结束时由操作系统回收。它与数据结构中的堆是两回事,分配方式类似于链表。
    • 全局/静态区:全局变量和静态变量的存储是放在一块的,初始化的全局变量和初始化的静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后由操作系统回收。
    • 文字常量区:存放常量值,如常量字符串等,不允许修改,程序结束后由操作系统回收。
    • 程序代码区:存放函数体的二进制代码。
  • 例子如下:
#include <stdlib.h>
#include <string.h>
int a = 0; // 全局初始化区
char* p1;  // 全局未初始化区
int main() {
 int a;            // 栈区
 char s[] = "abc"; // 栈区
 char* p2;         // 栈区
 char* p3 = "123456";    // 123456\0在常量区,p3在栈区
 static int c = 0;      // 全局/静态初始化区
 p1 = (char*) malloc(10);
 p2 = (char*) malloc(20); // 分配得来的10和20字节在堆区
 strcpy(p1, "123456"); // 123456\0放在常量区,编译器可能将它与p3所指向的"123456"优化成一个地方
 return 0;
}

new与malloc的区别

  • 属性

    • new/delete是操作符,是C++关键字,需要编译器支持;malloc/free是库函数,需要头文件支持。
  • 参数
    • 使用new操作符动态分配内存时无需指定内存块大小,编译器会根据类型自行计算;malloc分配内存时需要显式地指出所需内存块大小。
  • 返回类型
    • new操作符内存分配成功时会返回相应对象类型的指针,无需进行强制类型转换,符合类型安全性,分配失败时会抛出bac_alloc异常;malloc分配内存成功时会返回void*类型的指针,需要通过强制类型转换为所需类型,分配失败时返回NULL值。
  • 非内部数据对象
    • new会先调用operator new函数,申请足够的内存,再调用类型的构造函数,初始化成员变量,最后返回自定义类型的指针;delete会先调用析构函数,然后调用operator delete函数释放内存;malloc/free是库函数,只能动态申请内存及释放内存,无法完成构造函数及析构函数的工作。
  • 重载
    • C++允许重载new/delete(实际上是重载operator new 和operator delete),特别的,布局new(placement new)就不需要为对象分配内存,而是使用指定一个地址作为内存起始区域,new在这段内存上完成对象的构造函数调用并初始化该内存段,并返回此内存地址;malloc/free不允许重载。
  • 内存区域
    • new操作符从自由存储区(free stone)上为对象动态分配空间,malloc函数从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请的,该内存即为自由存储区;堆是操作系统中已分配的对应的内存区域。自由存储区不等于堆,布局new就可以不位于堆中。堆是一个实际的区域,而自由存储区是一个更上层的概念。通常new确实是在堆上申请内存,但是程序员可以自己重载new操作符,使用其他内存来实现自由存储(不常见),另外,C++primer plus这本书上提到的布局new,可以为对象在栈上分配内存。总的来说,自由存储区是new申请的区间的概念。

3种类间关系及区别

Inheritance(继承)

  • 表示is-a,如下代码所示:
class A {
private:
    int a;
};

class B : public A {
private:
    int b;
};
  • 继承关系下的构造和析构

    ==构造由内而外==

    Derived的构造函数首先调用Base的default构造函数,然后才执行自己。如,Derived::Derived(...) : ==Base()== { ... };

    ==析构由外而内==

    Derived的析构函数首先执行自己,然后才调用Base的析构函数。如,Derived::~Derived(...) { ... ==~Base()== };

Composition(复合)

  • 表示has-a,如下代码所示:
class A {
private:
    int a;
};

class B {
private:
    A a;
    int b;
};
  • 复合关系下的构造和析构

    ==构造由内而外==

    B的构造函数首先调用A的default构造函数,然后才执行自己。如,B::B(...) : ==A()== { ... };

    ==析构由外而内==

    B的析构函数首先执行自己,然后才调用A的析构函数。如,B::~B(...) { ... ==~A()== };

Delegation(委托)

  • Composition by reference, 如下代码所示:
class A {
private:
    int a;
};

class B {
private:
    A* a;
    int b;
};

原文地址:https://www.cnblogs.com/yiluyisha/p/9188010.html

时间: 2024-11-13 08:50:35

C++:一些常见知识点的区别(整理)的相关文章

常见数据结构与算法整理总结(上)

数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作.算法是为求解一个问题需要遵循的.被清楚指定的简单指令的集合.下面是自己整理的常用数据结构与算法相关内容,如有错误,欢迎指出. 为了便于描述,文中涉及到的代码部分都是用Java语言编写的,其实Java本身对常见的几种数据结构,线性表.栈.队列等都提供了较好的实现,就是我们经常用到的Java集合框架,有需要的可以阅读这篇文章.Java - 集合框架完全解析 一.线性表 1.数组实现 2.链表 二.栈与队列 三.树

iOS 常见知识点(三):Lock

iOS 常见知识点(一):Runtime iOS 常见知识点(二):RunLoop 锁是最常用的同步工具.一段代码段在同一个时间只能允许被有限个线程访问,比如一个线程 A 进入需要保护代码之前添加简单的互斥锁,另一个线程 B 就无法访问,只有等待前一个线程 A 执行完被保护的代码后解锁,B 线程才能访问被保护代码. iOS 中的八大锁 NSLock @protocol NSLocking - (void)lock; - (void)unlock; @end @interface NSLock :

scanf,fscanf,sscanf的区别----整理

转自原文 scanf,fscanf,sscanf的区别----整理 scanf 从控制台输入 fscanf 从文件输入 sscanf 从指定字符串输入 1.例:使用scanf函数输入数据. #include<stdio.h> int main() { int a,b,c; printf("输入 a, b, c\n"); scanf("%d,%d,%d", &a, &b, &c); printf("a = %d b = %

Linux常见命令及常见知识点

Linux常见命令及常见知识点(学习) 绝对路径表示, 如:/etc/http.d 当前目录: ./ 上层目录: ../ 主目录:~/ 切换目录:cd 查看当前路径: pwd 查看当前进程:ps 显示所有进程: ps -ef (system v 输出) / ps -aux bsd 格式输出 查看指定进程信息:ps -ef | grep pid 执行退出:exit 清屏:clear 退出当前命令: ctrl + c (彻底退出) 执行睡眠:ctrl + z (挂起当前进程 恢复后台) 查看当前用户

Vue常见知识点

I. 什么是 MVVM? MVVM是 Model-View-ViewModel 的缩写.它是一种设计思想.Model 层代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑:View 代表UI组件,它负责将数据模型转化成 UI展现出来:ViewModel 是一个同步 View 和 Model 的对象. 在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过 ViewModel 进行交互,Model 和 ViewModel之间的交互是双向的,因此 View 数据的

IHttpModule与IHttpHandler的区别整理

IHttpModule与IHttpHandler的区别整理1.先后次序.先IHttpModule,后IHttpHandler. 注:Module要看你响应了哪个事件,一些事件是在Handler之前运行的,一些是在Handler之后运行的2.对请求的处理上:IHttpModule是属于大小通吃类型,无论客户端请求的是什么文件,都会调用到它;例如aspx,rar,html的请求.IHttpHandler则属于挑食类型,只有ASP.net注册过的文件类型(例如aspx,asmx等等)才会轮到调用它.3

常见的布局方法整理[兼容]

一行两列左侧固定右侧自动适应 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv

ref与out之间的区别整理 摘自与望楼http://blog.csdn.net/xiaoning8201/article/details/6893154

ref和out都是C#中的关键字,所实现的功能也差不多,都是指定一个参数按照引用传递. 对于编译后的程序而言,它们之间没有任何区别,也就是说它们只有语法区别. 总结起来,他们有如下语法区别: 1.ref传进去的参数必须在调用前初始化,out不必,即: int i; SomeMethod( ref i );//语法错误 SomeMethod( out i );//通过 2.ref传进去的参数在函数内部可以直接使用,而out不可: public void SomeMethod(ref int i)

javaScript中一些常见的兼容性问题整理

javaScript中一些常见的兼容性问题整理 1)滚动条: document.documentElement.scrollTop||document.body.scrollTop 2) 获取样式兼容 functiongetStyle(dom, styleName){ return dom.currentStyle? dom.currentStyle[styleName] getComputedStyle(dom)[styleName]; } 3) 网页可视区域兼容 window.innerHe