C++超详细讲解内存空间分配与this指针

目录
  • 成员属性和函数的存储
    • 空对象
    • 成员属性的存储
    • 成员函数的存储
  • this指针的概念
    • 解决名称冲突
    • 返回对象指针*this
  • 总结

成员属性和函数的存储

在C++中成员变量和成员函数是分开存储的;

空对象

class Person {};

这里我直接创建一个空的类,并创建一个空的类对象(Person p),利用sizeof关键字输出p所占内存空间,sizeof(p);结果是p=1;

注意:空对象占用内存空间为:

1、C++编译器会给每个空对象分配一个字节空间,是为了区分空对象占内存的位置

2、每个空对象也应该有一个独一无二的内存地址

成员属性的存储

class Person
{
public:
	int m_A;
    static int m_B;
};
int Person::m_B = 100;

首先创建一个简单的Person类,仅仅包含普通成员属性m_A和静态成员变量m_B;然后直接利用sizeof关键字输出p所占内存空间:sizeof(p)

这里的结果是4,而不是8,这是因为静态成员属性不属于类的对象上,无论再加几个静态成员属性,都不会改变结果是4,但是一旦普通成员属性,就会多占用内存空间,比如我加一个float类型的m_c属性,结果是:

成员函数的存储

class Person
{
public:
	void func1(){}
	static void func2(){}//函数都不属于类的对象上,只有非静态成员变量才占用类对象内存空间.
};

这里的Person类中加了普通成员函数和静态成员函数,他们所占内存空间的情况是什么呢,让我们看看结果:

为什么结果和空对象一样呢,因为我开头就说了,C++中成员变量和成员函数是分开存储的,无论是怎样的成员函数都不会占用类对象的内存空间。

小结:函数都不属于类的对象上,只有非静态成员变量才占用类对象内存空间.

this指针的概念

从上面的内容我们知道C++中成员变量和成员函数是分开存储的,每一非静态成员函数只会诞生一份函数实例,也就是说,多个同类型的对象会公用一块代码。

那么问题是:这一块代码是如何区分哪个对象调用自己呢?C++通过特殊的对象指针,this指针解决上述问题。this指针指向被调用的成员函数所属的对象。 this指针是隐含每一个非静态成员函数内的一个指针,不需要定义,直接使用即可。

作用:

1、解决名称冲突

2、返回对象指针*this

解决名称冲突

class Person
{
public:
	Person(int age)
	{
		//this 指针指向 被调用的成员函数 所属的对象
		this->age = age;
	}
	int age;
};

如果我们在编写代码的时候,写的属性太多了,导致成员属性和要传入的变量名相同,就会引发不必要的bug;这时候加上一个this,就可以完美的解决这个问题,this->+属性名,表示指向被调用的成员函数所属的对象,那样我们这个有参构造函数的赋值问题就很好的解决了。

返回对象指针*this

class Person
{
public:
	Person(int age)
	{
		this->age = age;
	}
	Person(const Person& p)
	{
		cout << "拷贝构造函数调用" << endl;
		cout << &p << endl;
	}
	Person& PersonAddAge(Person &p);
	int age;
};
Person& Person::PersonAddAge(Person &p)//返回引用形式地址不变,可以一直加年龄
{
	this->age += p.age;
	cout << &*this << endl;
	return *this;
}

既然this指针指向这个对象的地址,那么*this就代表这个对象的本身,我们做一个年龄相加的成员方法来测试一下;

void test02()
{
	Person p1(10);
	Person p2(10);
	//p1.PersonAddAge(p2).PersonAddAge(p2);//链式调用,返回不加&结果都是20,调用拷贝构造;
	p1.PersonAddAge(p2).PersonAddAge(p2).PersonAddAge(p1).PersonAddAge(p1);
	cout << "p1 年龄为:" << p1.age;
}

大家可以猜猜这样输出的p1的年龄是多少,正确答案是120,其中的“.+函数”属于链式调用,可以快速调用函数,非常之方便好用。之所以是120,原因是这四次调用中,第一次返回p1的年龄属性为10+10,第二次为20+10,第三次为30+30,第四次为60+60=120。是不是看着很简单,但有一个特别注意的事情;相信有心的伙伴已经看到PersonAddAge函数返回值类型是Person &,返回的是类的引用,为什么不返回类的值呢?

这里注意,如果去掉“&”直接返回类的值的话,是没法继续链式调用的,因为前面讲过返回类型为类对象时,这个返回的类对象会被清理掉,然后调用拷贝构造函数在新的地址创建一个类对象,虽然属性结果一样,但是地址变了,可以输出地址看看:

由此可见,去掉“&”四次调用产生了四个地址,而无论多用多少次增加年龄函数,最终结果也只能是20,因为我们输出的是p1的值,从第二次调用,都和p1没关系了,地址已经变了。

再和返回引用的做一下对比:

显而易见,返回类引用不会调用构造函数,p1的地址不变,就能成功的累加年龄了!!!

总结

学习了这一节我们一定要知道C++成员属性和成员函数是分开存储的,以及this指针的妙用;再使用返回对象指针*this的时候,如果想继续对此对象的属性进行修改,一定要加上“&”引用符,如果单纯为了显示的话,可以不加。好了,今天的分享结束了,我们“明天见”。

到此这篇关于C++超详细讲解内存空间分配与this指针的文章就介绍到这了,更多相关C++内存空间分配内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 一起来学习C++中类的this指针以使用

    目录 一,this指针的注意点 错误用例: 二,this指针存在哪里 三,this指针的面试坑题 总结 c++的类中,非静态的成员函数都有一个隐藏的this指针,在函数体中所以的成员变量都是通过this指针来访问的.但是this指针是对用户是透明的,用户不需要显示的给this指针传参,编译时会自动接收参数. 一,this指针的注意点 调用成员函数时,不可以显示给this指针传参 定义成员函数时,不能显示的声明this指针 在成员函数内部,可以显示的使用this指针 用一个日期类,来讲述this指

  • C++对象模型和this指针详解

    目录 对象模型 一. 二. 三. 四. 五. this指针 一. 二. 总结 对象模型 成员变量和成员函数分开存储 一. 只有非静态成员变量才属于类的对象上 空对象占用字节为1 class Person { }; void test01() { Person p; cout << "size of = " << sizeof(p) << endl; } int main() { test01(); system("pause");

  • c++动态内存空间示例(自定义空间类型大小和空间长度)

    动态内存空间的申请示范 利用C++的特性,能够自定义空间的类型大小和空间长度 下面这个程序是个数组动态配置的简单示例 复制代码 代码如下: #include <iostream>using namespace std; int main(){   int size = 0; cout << "请输入数组长度:";  //能够自定义的动态申请空间长度    cin >> size;    int *arr_Point = new int[size];

  • C++ 中this指针的用途详解

    目录 1.区分形参和变量同名时: 2.return *this返回函数本身 总结 先说结论: 1.形参和变量同名时,可用this指针来区分 2.在类的非静态成员函数中返回本身,可用return *this 1.区分形参和变量同名时: #include <iostream> using namespace std; class Person { public: Person(int age) { age = age; } int age; }; void test01() { Person p1

  • C++深入探究类与对象之对象模型与this指针使用方法

    目录 C++对象模型和this指针 1 成员变量和成员函数分开存储 2 this指针概念 3 空指针访问成员函数 4 const修饰成员函数 C++面向对象的三大特性为:封装.继承.多态 C++认为万事万物都皆为对象,对象上有其属性和行为 例如: ​ 人可以作为对象,属性有姓名.年龄.身高.体重…,行为有走.跑.跳.吃饭.唱歌… ​ 车也可以作为对象,属性有轮胎.方向盘.车灯…,行为有载人.放音乐.放空调… ​ 具有相同性质的对象,我们可以抽象称为类,人属于人类,车属于车类 C++对象模型和th

  • C++函数指针+对象指针+this指针+指向类静态和非静态成员的指针

    目录 1.指向函数的指针 2.对象指针 3.this指针 4.指向类的非静态成员的指针 5.指向类的静态成员的指针 1.指向函数的指针 函数的代码在内存中的首地址,是由函数名表示的,也就是说函数名等价于函数代码首地址.因此,可以定义一个指向函数的指针,即函数指针.函数指针定义和赋值的语法如下,其中数据类型代表指向函数的返回类型,形参表为指向函数的形参表:赋值时必须保证指向的函数名和函数指针的返回类型和形参完全相同: 数据类型 (*函数指针名)(形参表);函数指针名 = 函数名; 下面的例子定义了

  • C++this指针详情

    还是Stock股票这个类,假设我们要实现一个方法,比较一下当前股票和传入的股票, 返回价格高的那个股票.在我们实现的时候,会遇到一点问题. const Stock & Stock::topVal(const Stock &s) const {     if (s.total_val > total_val) {         return s;     }else {         return ????;     } } 这段代码当中有一些问题,我们一个一个来说. 首先说函数签

  • C++深入浅出讲解隐藏this指针的用法

    目录 1.this指针的引出 2.this指针的特性 3.练习一下 本篇文章我们将一起讨论在有趣的知识点--隐藏的this指针.本篇我们要使用到之前我们所学习到的C++类与对象,如果有各位小伙伴还不曾了解类与对象的简单思想,可以访问上篇: 在之后的学习中,我们将认识一个新的类:日期类Date.正如我们所想的那样,传入一个日期,我们可以输出我们所输入的日期. 1.this指针的引出 那我们首先来看一下,这段代码会输出什么结果呢? class Date { public: void Display(

  • C++超详细讲解内存空间分配与this指针

    目录 成员属性和函数的存储 空对象 成员属性的存储 成员函数的存储 this指针的概念 解决名称冲突 返回对象指针*this 总结 成员属性和函数的存储 在C++中成员变量和成员函数是分开存储的: 空对象 class Person {}; 这里我直接创建一个空的类,并创建一个空的类对象(Person p),利用sizeof关键字输出p所占内存空间,sizeof(p);结果是p=1: 注意:空对象占用内存空间为: 1.C++编译器会给每个空对象分配一个字节空间,是为了区分空对象占内存的位置 2.每

  • Python超详细讲解内存管理机制

    目录 什么是内存管理机制 一.引用计数机制 二.数据池和缓存 什么是内存管理机制 python中创建的对象的时候,首先会去申请内存地址,然后对对象进行初始化,所有对象都会维护在一 个叫做refchain的双向循环链表中,每个数据都保存如下信息: 1. 链表中数据前后数据的指针 2. 数据的类型 3. 数据值 4. 数据的引用计数 5. 数据的长度(list,dict..) 一.引用计数机制 引用计数增加: 1.1 对象被创建 1.2 对象被别的变量引用(另外起了个名字) 1.3 对象被作为元素,

  • C语言数据的存储超详细讲解下篇浮点型在内存中的存取

    目录 前言 浮点型在内存中的存储 浮点数存储的例子 浮点数存储规则 IEEE 754规定 IEEE 754对有效数字M的特别规定 IEEE 754对指数E的特别规定 存入内存是E的规定 从内存取出时E的规定 举例 1 举例 2 举例 3 判断两个浮点数是否相等? 总结 前言 本文接着学习数据的存储相关的内容,主要学习浮点型数在内存中的存储与取出. 浮点型在内存中的存储 常见的浮点数:3.14159.1E10 浮点数家族包括: float.double.long double 类型 浮点数表示的范

  • C语言超详细讲解字符串函数和内存函数

    目录 字符串函数 长度不受限制的字符串函数 strlen strcpy strcat strcmp 长度受限制的字符串函数介绍 strncpy strncat strncmp 字符串查找以及错误报告 strstr strtok strerror 内存操作函数 memcpy memmove memcmp 字符串函数 长度不受限制的字符串函数 strlen size_t strlen ( const char * str ) 求字符串长度: 字符串以'\0' 作为结束标志,strlen函数返回的是在

  • C语言可变参数与内存管理超详细讲解

    目录 概述 动态分配内存 重新调整内存的大小和释放内存 概述 有时,您可能会碰到这样的情况,您希望函数带有可变数量的参数,而不是预定义数量的参数.C 语言为这种情况提供了一个解决方案,它允许您定义一个函数,能根据具体的需求接受可变数量的参数.下面的实例演示了这种函数的定义. int func(int, ... ) { . . . } int main() { func(2, 2, 3); func(3, 2, 3, 4); } 请注意,函数func()最后一个参数写成省略号,即三个点号(...)

  • java反射超详细讲解

    目录 Java反射超详解✌ 1.反射基础 1.1Class类 1.2类加载 2.反射的使用 2.1Class对象的获取 2.2Constructor类及其用法 2.4Method类及其用法 Java反射超详解✌ 1.反射基础 Java反射机制是在程序的运行过程中,对于任何一个类,都能够知道它的所有属性和方法:对于任意一个对象,都能够知道它的任意属性和方法,这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制. Java反射机制主要提供以下这几个功能: 在运行时判断任意一个对象所属

  • 超详细讲解Linux C++多线程同步的方式

    目录 一.互斥锁 1.互斥锁的初始化 2.互斥锁的相关属性及分类 3,测试加锁函数 二.条件变量 1.条件变量的相关函数 1)初始化的销毁读写锁 2)以写的方式获取锁,以读的方式获取锁,释放读写锁 四.信号量 1)信号量初始化 2)信号量值的加减 3)对信号量进行清理 背景问题:在特定的应用场景下,多线程不进行同步会造成什么问题? 通过多线程模拟多窗口售票为例: #include <iostream> #include<pthread.h> #include<stdio.h&

  • 超详细讲解python正则表达式

    目录 正则表达式 1.1 正则表达式字符串 1.1.1 元字符 1.1.2 字符转义 1.1.3 开始与结束字符 1.2 字符类 1.2.1 定义字符类 1.2.2 字符串取反 1.2.3 区间 1.2.4 预定义字符类 1.3 量词 1.3.1 量词的使用 1.3.2 贪婪量词和懒惰量词 1.4 分组 1.4.1 分组的使用 1.4.2 分组命名 1.4.3 反向引用分组 1.4.4 非捕获分组 1.5 re模块 1.5.1 search()和match()函数 1.5.2 findall()

  • 超详细讲解Java异常

    目录 一.Java异常架构与异常关键字 Java异常简介 Java异常架构 1.Throwable 2.Error(错误) 3.Exception(异常) 4.受检异常与非受检异常 Java异常关键字 二.Java异常处理 声明异常 抛出异常 捕获异常 如何选择异常类型 常见异常处理方式 1.直接抛出异常 2.封装异常再抛出 3.捕获异常 4.自定义异常 5.try-catch-finally 6.try-with-resource 三.Java异常常见面试题 1.Error 和 Excepti

  • C语言 超详细讲解链接器

    目录 1 什么是链接器 2 声明与定义 3 命名冲突 3.1 命名冲突 3.2 static修饰符 4 形参.实参.返回值 5 检查外部类型 6 头文件 1 什么是链接器 典型的链接器把由编译器或汇编器生成的若干个目标模块,整合成一个被称为载入模块或可执行文件的实体–该实体能够被操作系统直接执行. 链接器通常把目标模块看成是由一组外部对象组成的.每个外部对象代表着机器内存中的某个部分,并通过一个外部名称来识别.因此,==程序中的每个函数和每个外部变量,如果没有被声明为static,就都是一个外部

随机推荐