c++面向对象概述、内存分析、引用、函数

简介: c++面向对象概述、内存分析、引用、函数

1.c++内存分区模型

c++程序在运行的过程中,内存会被划分为以下四个分区

代码区:程序的所有程序的二进制代码,包括注释会被放到此区

全局区:存放静态变量、全局变量、常量(字符串常量和const修饰的常量),此区的数据将在程序结束后由操作系统释放

using namespace std;
//不在任何函数内的变量是全局变量
int a = 10;
int b = 23;
 
int main() {
  //在某个函数内的变量
  int c = 12;
  cout << (int)&a << endl;
  cout << (int)&b << endl;
  cout << (int)&c << endl;
 
}

栈区:用于存放局部变量、函数参数等,是由编译器自动释放和分配,所以不能让栈区返回一个地址,

#include <iostream>
#include <string>
using namespace std;
 
int* f() {
  int a = 10;
  return &a;//栈区不要返回地址。局部变量是由编译器自动释放和分配
}
int main() {
  
  int* p = f();
  cout << *p;//10 第一次编译器会做保留
  cout << *p;//不会打印10
}

堆区:存储对象(使用new操作符,后面会介绍)由程序员分配释放,若我们不释放,程序结束由操作系统释放

c++中通过new关键字将数据开辟到堆区

#include <iostream>
using namespace std;
int* f() {
  /*
  *1.指针本身也是局部变量,存放在栈长中,但是保存的数据在堆中
  2.new关键字开辟一块堆区,返回的是该数据类型的指针
  */
  int *a = new int(10);
  return a;
}
int main() {
  int* p = f();
  cout << *p;//10
  cout << *p;//10
  //3.堆区的数据程,序员可以通过该delete释放
  delete p;
  //cout << *p;异常
}

如果是new一个数组

//new一个数组
int* arr = new int[10];
//释放一个数组
delete[] arr;

注意

代码区和全局区是程序编译成exe可执行文件的时候就已经有了,但是栈区和堆区是程序exe文件执行后产生的

2.为什么划分内存(内存划分意义)

将不同的数据放在不同的区域,赋予不同的生命周期,提高编程灵活程度

3.引用

使用引用给一个变量起别名

#include <iostream>
using namespace std;
 
int main() {  
  int a = 10;
  /*1.定义引用的格式  数据类型 &别名=原名
  *2.引用必需要初始化
  *3.引用初始化后,不可更改
  */
  int& b = a;
  cout << b;//10
}

前面文章中的地址传递会修改实参,值传递不会修改实参,引用作为函数参数会修改实参,简化使用指针修改实参的复杂过程

#include <iostream>
using namespace std;
void swap(int &a,int &b) {
  int temp = a;
  a = b;
  b = temp;
}
int main() {  
  int a = 10;
  int b = 20;
  swap(a,b);
  cout << a;//20
  cout << b;//10
}

局部变量不能作为函数的返回值返回

#include <iostream>
using namespace std;
int& f() {
  int a = 10;//栈区中的局部变量在函数执行完后释放
  return a;
}
int main() {  
  int &a = f();
  cout << a;//10 编译器保留
  cout << a;//不在是10
}

如果是局部静态变量,可以返回

#include <iostream>
using namespace std;
int& f() {
  static int a = 10;//栈区中的局部变量在函数执行完后释放
  return a;
}
int main() {  
  int &a = f();
  cout << a;//10
  cout << a;//10
}
#include <iostream>
using namespace std;
int& f() {
  static int a = 10;//栈区中的局部变量在函数执行完后释放
  return a;
}
int main() {  
  int &a = f();
  cout << a;//10
  cout << a;//10
  f() = 100;//如果函数的返回是一个引用,可以作为左值
  cout << a;//100
  cout << a;//100
}

引用本质是指针常量

int main() {  
  int a = 1;
  //内部发现是引用,自动转成指针常量 int * const b=&a;
  int& b = a;
  b = 2;//内部发现是引用,自动转成*b=20;
  cout << a;//2
  cout << b;//2
}

常量引用

#include <iostream>
using namespace std;
//使用const修改函数形参,防止误操作
void f(const int& a) {
  //a = 100;不允许修改
}
int main() {  
  int& b = 1;//引用本身需要一个合法内存空间,所以这行代码有误
  int a = 10;
  f(a);
}

 

4.函数相关

前面c++基础系列有关函数知识有所描述,这里补充一些函数高级知识

1.c++中函数可以有默认值

#include <iostream>
using namespace std;
//1.c++中函数可以有默认值,并且某个位置有了默认值,那么从这个位置开始左到右都的有默认值
int f(int a, int b = 10,int c=20) {
  return a + b + c;
}
int main() {  
  int a = 10;
  //2.如果函数有默认值,当我们传值使用传递的值,不传值使用默认的
  cout<<f(a);//40
  cout << f(a, 20);//50
}
//3.声明和实现只能有一个有默认参数
int f1(int a, int b = 10);
int f1(int a, int b) {
  return a + b;
}

2.c++函数中可以有占位参数用来占位,调用函数必需填补该位置

#include <iostream>
using namespace std;
 
//1.只写一个数据类型就是占位
void f(int a,int) {
  cout << "test";
}
//2.占位参数可以有默认值
void f1(int a, int=10) {
  cout << "test";
}
int main() {  
  int a = 10;
  f(a, 10);//占位参必须填补
}

3.函数重载

定义:同一个作用域下,两个函数参数类型不同或者参数顺序不同或者个数不同。此时这两个函数名字可以相同。提高复用性

#include <iostream>
using namespace std;
 
void f(int a,int b) {
  cout << "test";
}
 
void f(int a) {
  cout << "test";
}
int main() {  
  int a = 10;
  f(a, 10);
}

注意:函数返回值不能作为函数重载的条件

4.引用也可作为函数重载条件

#include <iostream>
using namespace std;
 
void f(int &a) {//int &a=10;不合法
  cout << "test";
}
 
void f(const int &a) {//const int &a=10;合法
  cout << "test111";
}
int main() {  
  int a = 10;
  f(a);//test
  f(10);//test111
}

5.函数重载遇到默认参数需要注意

void f(int a,int b=10) {//int &a=10;不合法
  cout << "test";
}
 
void f(int a) {//const int &a=10;合法
  cout << "test111";
}
int main() {  
  int a = 10;
  f(a);//报错,出现二义性
}



相关文章
|
3月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
44 3
|
2天前
|
存储 算法 安全
基于哈希表的文件共享平台 C++ 算法实现与分析
在数字化时代,文件共享平台不可或缺。本文探讨哈希表在文件共享中的应用,包括原理、优势及C++实现。哈希表通过键值对快速访问文件元数据(如文件名、大小、位置等),查找时间复杂度为O(1),显著提升查找速度和用户体验。代码示例展示了文件上传和搜索功能,实际应用中需解决哈希冲突、动态扩容和线程安全等问题,以优化性能。
|
8天前
|
存储 缓存 编译器
【硬核】C++11并发:内存模型和原子类型
本文从C++11并发编程中的关键概念——内存模型与原子类型入手,结合详尽的代码示例,抽丝剥茧地介绍了如何实现无锁化并发的性能优化。
|
1月前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
64 6
|
2月前
|
存储 缓存 C语言
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
58 3
|
2月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
152 4
|
2月前
|
Ubuntu Linux Shell
C++ 之 perf+火焰图分析与调试
【11月更文挑战第6天】在遇到一些内存异常的时候,经常这部分的代码是很难去进行分析的,最近了解到Perf这个神器,这里也展开介绍一下如何使用Perf以及如何去画火焰图。
107 5
|
3月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
3月前
|
存储 C语言 C++
【C++打怪之路Lv6】-- 内存管理
【C++打怪之路Lv6】-- 内存管理
56 0
【C++打怪之路Lv6】-- 内存管理
|
3月前
|
Ubuntu Linux Shell
C++ 之 perf+火焰图分析与调试
【10月更文挑战第8天】在遇到一些内存异常的时候,经常这部分的代码是很难去进行分析的,最近了解到Perf这个神器,这里也展开介绍一下如何使用Perf以及如何去画火焰图。