内存、引用、封装、函数

简介: 内存、引用、封装、函数

内存

内存分区模型

代码区:存放函数体的二进制代码,由操作系统进行管理

全局区:存放全局变量、静态变量和常量

栈区:由编译器自动分配释放,存放函数的参数值、局部变量等

堆区:由程序员分配释放,若程序员不释放,程序结束时由操作系统回收

内存分区意义:不同分区存放的数据,赋予不同的生命周期,灵活编程

程序运行前

程序编译后,生成.exe可执行程序,未执行该程序前,分为两个区域:

代码区:

  • 存放CPU执行的机器指令
  • 代码区是共享的,目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
  • 代码区是只读的,防止程序意外的修改了它的指令

全局区:

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

程序运行后

栈区:

由编译器自动分配释放,存放函数的参数值、局部变量等

注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放

int* test()//形参也会存放在栈区
{
    int a = 10;//局部变量,存放在栈区,栈区的数据在函数执行完后被自动释放
    return &a;//返回局部变量地址
}

堆区:

由程序员分配释放,若程序员不释放,程序结束时,由操作系统回收

在C++中主要利用new在堆区开辟内存

int* test()
{
    //利用new关键字,可以将数据开辟到堆区
    //指针也是局部变量,放在栈上,指针保存的数据是放在堆区
    int* p = new int(10);
    return p;
}

new操作符

new在堆区开辟数据,释放利用delete

利用new创建的数据,会返回该数据对应的类型的指针

void test()
{
    int* p = new int(10);
    cout << *p << endl;
    delete p;
    cout << *p << endl;//使用未初始化的内存p
}

也可以加中括号[]开辟或释放数组

void test()
{
    int* p = new int[10];
    for (int i = 0; i < 10; i++)
    {
        *(p + i) = i;
    }
    for (int i = 0; i < 10; i++)
    {
        cout << *(p + i) << endl;
    }
    //释放数组时,要加中括号才可以
    delete[] p;
}

作用:给变量起别名

语法数据类型 &别名 = 原名

int main()
{
    int a = 10;
    //引用必须初始化,一旦初始化,就不可以更改
    int& b = a;
    b = 100;
    cout << "a=" << a << endl;//100
    cout << "b=" << b << endl;//100
    return 0;
}

引用

引用作函数参数

作用:函数传参时,可以利用引用的技术让形参修饰实参

优点:可以简化指针 修改实参

//引用传递
void test2(int& a, int& b)
{
    int temp = a;
    a = b;
    b = temp;
}
int main()
{
    int a = 10, b = 20;
    test2(a, b);//引用传递
    cout << "a=" << a << endl;//20
    cout << "b=" << b << endl;//10
    return 0;
}

通过引用参数产生的效果和地址传递是一样的,引用的语法更清楚简单

引用作函数返回值

  • 不要返回局部变量引用
  • 函数的调用可以作为左值
int& test()
{
    //静态变量存放在全局区,程序结束时由系统释放
    static int a = 10;
    return a;
}
int main()
{
    int& a = test();
    cout << a << endl;//10
    cout << test() << endl;//10
    //函数调用可以作为左值
    test() = 100;
    cout << a << endl;//100
    cout << test() << endl;//100
    return 0;
}

引用的本质

本质:一个指针常量

C++推荐用引用技术,因为语法方便,引用本质是指针常量,但是所有的指针操作,编译器都帮我们做了

//发现是引用,转化为int* const ref =&a;
void test(int& ref)
{
    ref = 100;
}
int main()
{
    int a = 10;
    //自动转换为int* const ref =&a;指针常量是指针指向不可改,也说明为什么引用不可改
    int& ref = a;
    //内部发现是引用,自动转换为:*ref = 20;
    ref = 20;
    cout << "a=" << a << endl;//20
    cout << "ref=" << ref << endl;//20
    test(a);
    cout << "a=" << a << endl;//100
    return 0;
}

常量引用

用来修饰形参,防止误操作

引用要引用合法的内存空间:const int& a = 10;

void test(const int& a)
{
···
}

函数

函数默认参数

注意事项:

  • 如果某个位置已经有了默认参数,则从这个位置往后,从左到右,都必须有默认值
  • 函数声明和函数实现,只能有一个有默认参数
//如果某个位置已经有了默认参数,则从这个位置往后,从左到右,都必须有默认值
void test0(int a, int b = 10, int c = 10)
{
    cout << a + b + c << endl;
}
//函数声明和函数实现,只能有一个有默认参数
int test1(int a = 10, int b = 10);
int main()
{
    test0(5, 1);//16
    cout << test1() << endl;//20
    return 0;
}
int test1(int a, int b)
{
    return a + b;
}

函数占位参数

C++函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置

语法返回值类型 函数名 (数据类型) {}

//占位参数也可以有默认参数
void test(int a, int = 10)
{
}

函数重载

作用:函数名可以相同,提高复用性

函数重载满足条件

  • 同一作用域下
  • 函数名称相同
  • 函数参数类型不同,或者个数不同,或者顺序不同

注意事项

  • 引用作为重载的条件
  • 当函数重载碰到默认参数,会出现二义性
//引用作为重载的条件
void test0(int& a)//int &a = 10;不合法
{
    cout << "test0" << endl;
}
void test0(const int& a)//const int &a = 10;合法
{
    cout << "test1" << endl;
}
int main()
{
    int a = 10;
    test0(a);//test0
    test0(10);//test1
    return 0;
}

C++面向对象的三大特性:封装继承多态

C++认为万事万物皆为对象,对象上有其属性和行为

具有相同性质的对象,我们可以抽象成为,人属于人类,车属于车类

封装

封装的意义

  • 将属性和行为作为一个整体,表现生活中的事物
  • 将属性和行为加以权限控制
class circle
{
    //访问权限
public://公共权限
    //属性
    int r;//半径
    //行为
    double c()//获取周长
    {
        return 2 * 3.14 * r;
    }
};
int main()
{
    //实例化:通过一个类,创建一个对象
    circle a;
    //给对象属性赋值
    a.r = 10;
    cout << a.c() << endl;//62.8
    return 0;
}

访问权限

  • public公共权限:成员 类内可以访问,类外可以访问
  • protected保护权限:成员 类内可以访问,类外不可访问,儿子可以访问父亲中的保护内容
  • private私有权限:成员 类内可以访问,类外不可访问,儿子不可以访问父亲中的私有内容

structclass区别

在C++中structclass唯一的区别在于默认的访问权限不同

  • struct默认权限为公共
  • class默认权限为私有
struct test1
{
    int a;
};
class test2
{
    int a;
};
int main()
{
    test1 a1;
    a1.a = 10;//可以访问
    test2 a2;
    a2.a = 10;//不可访问
    return 0;
}

成员属性私有化

优点

  • 将所有成员属性设置为私有,可以自己控制读写权限
  • 对于写权限,可以检测数据的有效性
class person
{
private:
    string name;
public:
    void setname(string name1)
    {
        name = name1;
    }
    string getname()
    {
        return name;
    }
};
int main()
{
    person a1;
    a1.setname("张三");
    cout << a1.getname() << endl;
    return 0;
}
目录
相关文章
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
33 3
|
27天前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
1月前
|
存储 程序员 编译器
C语言——动态内存管理与内存操作函数
C语言——动态内存管理与内存操作函数
|
22天前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
19 0
|
1月前
|
C语言 C++
c语言回顾-内存操作函数
c语言回顾-内存操作函数
39 0
|
1月前
|
存储 C语言 C++
来不及哀悼了,接下来上场的是C语言内存函数memcpy,memmove,memset,memcmp
本文详细介绍了C语言中的四个内存操作函数:memcpy用于无重叠复制,memmove处理重叠内存,memset用于填充特定值,memcmp用于内存区域比较。通过实例展示了它们的用法和注意事项。
64 0
|
1月前
一刻也没有为它哀悼~接下来登场的是动态内存分配的malloc与realloc以及free函数
一刻也没有为它哀悼~接下来登场的是动态内存分配的malloc与realloc以及free函数
65 0
|
3月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
366 0
|
21天前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
44 1
|
26天前
|
存储
共用体在内存中如何存储数据
共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。