类的概念、成员函数的定义方式、类的访问控制和封装、类的大小、this指针

文章目录

  • 类的概念
    • struct
    • class
    • class和struct的区别是什么呢?
  • 类中成员函数的两种定义方式
    • 声明和定义都在类中
    • 声明和定义分离
  • 类的访问控制和封装
    • 类的封装特性
  • 类的大小
    • 结构体内存对齐规则
    • 类的存储方式
  • this指针


类的概念

在C++中,类可以说是最重要的东西,因为C++一开始的定位就是c with class,也正是因为引入了类,才让c++从c的面向过程思想转变为面向对象的思想,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

C++有两种能够创建类的方法

struct

第一种是struct,也就是从C继承而来的,在C语言中,struct可以用来创建结构体,但是结构体中只能保存变量,而不能保存函数,在C++中,struct不仅可以用来创建类,还保留了C语言中结构体的用法

struct Date
{void PrintDate(){cout << _year << '-' << _month << '-' << _day << endl;}int _year;int _month;int _day;
};

class

class是C++中定义类的关键字,他的用法和struct类似。

在类中,类的元素被称为类的成员,类中的数据被称为成员变量或者类的属性,类中的函数被称为类的方法或者成员函数

class Date
{void PrintDate(){cout << _year << '-' << _month << '-' << _day << endl;}int _year;int _month;int _day;
};

class和struct的区别是什么呢?

  1. C++兼容C语言,所以struct不仅可以定义类,还可以当成结构体使用。
  2. 访问限定不同,struct的成员默认访问方式为public,class为private, 并且struct默认继承为public继承,,class为private

类中成员函数的两种定义方式

声明和定义都在类中

如果成员函数在类内部定义,则其是隐式的inline函数。

class Date
{void PrintDate(){cout << _year << '-' << _month << '-' << _day << endl;}int _year;int _month;int _day;
};

声明和定义分离

在类内声明,在类外定义,这样能让类更加简洁,不那么臃肿,通常都是使用这种方式。

class Date
{void PrintDate();int _year;int _month;int _day;
};//需要通过作用域运算符指定这个方法属于Date类
void Date::PrintDate()
{cout << _year << '-' << _month << '-' << _day << endl;
}

类的访问控制和封装

访问限定符有三种,分别是public,private,protected
在这里插入图片描述

  1. public修饰的成员在类外可以直接被访问。
  2. protected和private修饰的成员在类外不能直接被访问,protected修饰内容派生类可以访问,private不可以。
  3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。

类的封装特性

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行 交互。

封装本质上是一种管理:我们如何管理兵马俑呢?如果什么都不管,兵马俑可能会被随意破坏。那么我们首先建了一座房子把兵马俑给封装起来。但是我们目的并不是全封装起来,不让别人看。所以我们开放了售票通道,可以通过买票突破封装、在合理的监管机制下进去参观。类也是一样,我们将类数据和方法都封装一下。不想给别人肆意修改,我们使用protected/private把成员封装起来。同时开放一些共有的成员函数对成员合理的访问机制。所以封装本质是一种管理。

一般对于对象的属性,我们不希望别人对它进行修改,所以会用private将其封装,但是我们又需要给别人提供获取它的接口,所以会对方法和接口给与public属性。


类的大小

class Date
{
public:void PrintDate();private:char a;int _year;int _month;int _day;
};

我们可以看到,类中有成员函数,有成员变量,那么类的大小是如何计算的呢?

int main()
{Date d;cout << sizeof(d) << endl;
}

在这里插入图片描述
这里用sizeof查看大小,发现只有成员变量的大小(三个int类型一个char类型,3*4+1=13,这里的16是因为内存对齐偏移了3个字节),而没有成员函数的大小

结构体内存对齐规则

  1. 第一个成员在与结构体偏移量为0的地址处。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    注意:对齐数 = 编译器默认的一个对齐数该成员大小 两者中的较小值。(如int大小为4,VS中默认的对齐数为8,取4)
  3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小,本例中所有变量类型最大者是int,大小为4,与默认对齐参数取最小,则为4)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

类的存储方式

为什么会只保存了成员变量呢?这里就要引申出类的存储方式。

对于上面的类,如果我们将类实例化为多个对象,实际上这些对象不同的地方只有它的属性,它们调用的方法都是完全相同的, 为了不重复保存这些代码,C++只保存了属性,而将方法放到了公共的代码段中,来避免了空间的浪费。
在这里插入图片描述
同时,如果一个类中什么都没有,编译器会给这个类一个字节,来唯一标识这个类。
在这里插入图片描述
总结:类的大小就是成员变量之和(需要考虑内存对齐)


this指针

void Date::PrintDate()
{cout << _year << '-' << _month << '-' << _day << endl;
}

对于类中的成员函数,我们并没有将对象的属性传给他,那么他是如何能够获取这些属性的呢?

C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数(this指针),让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有对成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

其实类的成员函数中隐含了一个this指针,所以在编译器处理的时候,上面的代码等价于

void Date::PrintDate(Date * const this)
{cout << this->_year << '-' << this->_month << '-' << this->_day << endl;
}
  • 这个this指针的类型是类类型 * const this,之所以是顶层const的原因是因为this指针唯一指向对象地址。
  • this指针只能在成员函数中使用
  • this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针,this指针存在寄存器中。
  • this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递,

同时,如果this指针为空时,成员函数使用到了this指针,则会崩溃,如果没使用,则正常运行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443825.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jQuery实现两个列表框的值之间的互换:

jQuery实现两个列表框的值之间的互换&#xff1a; 截图如下&#xff1a; 代码如下&#xff1a; <% page language"java" import"java.util.*" pageEncoding"UTF-8"%> <%String path request.getContextPath();String basePath reque…

类的6个默认成员函数:构造函数、析构函数、拷贝构造函数、重载运算符、三/五法则

文章目录6个默认成员函数构造函数概念默认构造函数的类型默认实参概念默认实参的使用默认实参声明全局变量作为默认实参某些类不能依赖于编译器合成的默认构造函数第一个原因第二个原因第三个原因构造函数初始化构造函数里面的“”是初始化吗&#xff1f;为什么要使用列表初始化…

C++ 类的知识 | 构造函数再探、匿名对象、友元函数、内部类、类的const成员、类的static成员

文章目录构造函数再探以下代码共调用多少次拷贝构造函数委托构造函数概念形式匿名对象友元友元的声明友元类令成员函数作为友元函数重载和友元注意内部类特性类的const成员可变数据成员类的static成员概念关于static静态成员的类内初始化静态成员能用于某些普通成员不能的场景构…

顺序容器(vector、list、string、deque、forward_list)及迭代器、容器适配器

文章目录概述所有容器都支持的操作迭代器迭代器支持的操作迭代器支持的算术运算容器类型size_typeiterator 和 const_iterator容器定义和初始化拷贝初始化顺序容器独有的构造函数&#xff08;array除外&#xff09;array的初始化与内置数组类型的区别6种初始化方法&#xff08;…

jQuery实现表格隔行换颜色:

jQuery实现表格各行换颜色&#xff1a; 截图如下&#xff1a; 代码如下&#xff1a; <span style"font-family:Microsoft YaHei;font-size:14px;"><% page language"java" import"java.util.*" pageEncoding"UTF-8"%> &…

用stack处理中缀表达式【+、-、*、/、()】

文章目录题目描述思路使用getline()存储输入的字符串边读取边压栈完整代码题目描述 使用stack处理括号化的表达式。当你看到一个左括号&#xff0c;将其记录下来。当你在一个左括号之后看到一个右括号&#xff0c;从stack中pop对象&#xff0c;直至遇到左括号&#xff0c;将左括…

二维数组的查找

文章目录题目描述思路注意代码题目描述 在一个 n * m 的二维数组中&#xff0c;每一行都按照从左到右递增的顺序排序&#xff0c;每一列都按照从上到下递增的顺序排序。请完成一个高效的函数&#xff0c;输入这样的一个二维数组和一个整数&#xff0c;判断数组中是否含有该整数…

Springmvc,Spring MVC文件上传

Springmvc文件上传&#xff1a; 1.代码截图如下&#xff1a; 2.UploadController.java: package cn.csdn.controller;import java.io.File;import javax.servlet.http.HttpServletRequest;import org.springframework.stereotype.Controller; import org.springframework.ui.…

插入迭代器、流迭代器、反向迭代器、移动迭代器

文章目录前言插入迭代器inserterfront_inserterback_inserteriostream迭代器istream_iterator 读取输入流istream_iterator允许使用懒惰求值ostream_iterator操作反向迭代器reverse_iterator的base成员函数前言 除了为每个容器定义的迭代器之外&#xff0c;标准库在头文件iter…

泛型算法(lambda表达式、function类模板、bind函数适配器、迭代器类别、链表数据结构独有的算法)

文章目录概念find()函数迭代器令算法不依赖于容器但算法依赖于元素类型的操作算法永远不会执行容器的操作只读算法accumulate()函数从两个序列中读取元素&#xff08;equal函数为例&#xff09;迭代器作为参数形成两个序列equal()写容器元素的算法概念fill()fill_n()插入迭代器…

jsp,div 限制字数,超出部分用省略号代替

1.我是用struts2标签做的&#xff1a;如下&#xff1a; <% page language"java" import"java.util.*" pageEncoding"UTF-8"%> <% taglib prefix"s" uri"/struts-tags"%> <%String path request.getContext…

C++之关联容器

文章目录概述及类型mapsetpair类型概念初始化默认初始化提供初始化器允许的操作可以创建一个pair类的函数可以作为容器的类型关联容器迭代器概念map的迭代器set的迭代器是const的初始化map and setmultimap and multiset关联容器的操作额外的类型别名关联容器和算法删除元素添加…

动态内存、智能指针(shared_ptr、unique_ptr、weak_ptr)、动态数组

文章目录三种对象的分类三种内存的区别动态内存概念智能指针允许的操作智能指针的使用规范new概念内存耗尽/定位new初始化默认初始化直接初始化值初始化delete概念手动释放动态对象空悬指针shared_ptr类格式独有的操作make_shared函数shared_ptr的计数器通过new用普通指针初始化…

动态数组的简单应用

文章目录连接两个字符串字面常量题目注意代码输出结果处理输入的变长字符串题目注意代码连接两个字符串字面常量 题目 连接两个字符串字面常量&#xff0c;将结果保存在一个动态分配的char数组中。重写&#xff0c;连接两个标准库string对象。 注意 使用头文件cstring的str…

二分查找算法实现

文章目录思路代码以二分区间作为while判定条件以给定值作为while判定条件主函数思路 while判定条件的选择&#xff0c;注意最外层的return的内容就好。下面提供了两个代码版本。计算 mid 时需要防止溢出&#xff08;对应类型【如本例中的int】可能存不下&#xff09;&#xff…

根据中序、前序遍历重建二叉树

文章目录题目递归思路细节易错代码复杂度分析迭代思路细节易错代码复杂度分析题目 输入某二叉树的前序遍历和中序遍历的结果&#xff0c;请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 例如&#xff0c;给出 前序遍历 preorder [3,9,20,15,7] 中…

深搜+剪枝

文章目录题目思路注意代码复杂度分析题目 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c…

搜索+回溯问题(DFS\BFS详解)

文章目录题目思路DFS思路代码复杂度分析BFS思路代码复杂度分析题目 地上有一个m行n列的方格&#xff0c;从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动&#xff0c;它每次可以向左、右、上、下移动一格&#xff08;不能移动到方格外&#xff09;&am…

快速幂实现pow函数(从二分和二进制两种角度理解快速幂)

文章目录迭代实现快速幂思路int的取值范围快速幂从二进制的角度来理解从二分法的角度来理解代码复杂度分析进阶——超级次方思路倒序快速幂正序快速幂代码复杂度分析迭代实现快速幂 实现 pow(x, n) &#xff0c;即计算 x 的 n 次幂函数&#xff08;即&#xff0c;xn&#xff0…

n位数的全排列(需要考虑大数的情况)

文章目录题目思路代码题目 输入数字 n&#xff0c;按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3&#xff0c;则打印出 1、2、3 一直到最大的 3 位数 999。 示例 1: 输入: n 1 输出: [1,2,3,4,5,6,7,8,9] 说明&#xff1a; 用返回一个整数列表来代替打印 n 为正整数 …