接上篇:C++57个入门知识点_16 类的标准写法(类名、成员变量、成员函数及对象命名规则;成员变量一般为私有,成员函数为公有并暴露给外部使用成员变量;防止类过大,声明写在.h,实现写在.cpp,调用.h)。前面两篇介绍了面向对象的语言的特点、一个类应该怎样去写、访问权限,本篇将会讲 类的访问权限及C语言模拟类的封装。
总结:
1.类的访问权限及突破方法:
(1) 类的访问权限检查是在编译器进行的;在编译时期对访问权限进行限制,在程序运行时期可以进行修改;
(2)在运行期间可以通过指针修改内存值:*(int*)&clock = 111;
2. 利用函数指针在C语言中模拟类的封装: 利用函数指针typedef void((*PFN_SetHour)(int n));对结构体中的成员变量进行修改(可以用来感悟成员函数是属于整个类的)

1. 类的访问权限及突破方法

类的访问权限检查是在编译器进行的;在编译时期对访问权限进行限制,在程序运行时期可以进行修改

前面已知private只有在类域内可以访问,我们要讨论一个问题,访问的权限有没有办法突破呢?

下面为上篇中的代码,我们已经知道clock.m_nHour=1;在编译时是无法通过的,但是当程序运行之后,对象clock`是存在于内存中的,因此是否可以操作内存来修改对象的私有成员变量呢?

#include <iostream>class CClock {private:int m_nHour;int m_nMinute;int m_n_Second;public:void SetHour(int nHour){if (nHour >= 24 && nHour < 0){return;}m_nHour = nHour;};
};int main(int argc, char* argv[])
{CClock clock;clock.m_nHour=1;return 0;
}

1.1 通过调试器修改内存值

下面的代码给类的私有成员变量赋初值,通过内存去查看对象中成员变量的值,并通过调试器对内存中得值进行修改。

#include <iostream>class CClock {private:int m_nHour=1;int m_nMinute=2;int m_n_Second=3;public:void SetHour(int nHour){if (nHour >= 24 && nHour < 0){return;}m_nHour = nHour;};
};int main(int argc, char* argv[])
{CClock clock;return 0;
}

运行之后:内存中可以看到,私有变量具有初始值

1.2 CPU内存中大小尾排列方式

大家可能看到了,在内存中m_nHour的值是按照01 00 00 00排列的,而不是我们在二进制排列00 00 00 01,这是由于CPU的大小尾的关系相关,上面显示的是Intel CPU的方式。

大尾方式 即低地址数据在低位,高地址数据在高位(低低高高的排列方式),01 00 00 00四个数据对应地址分别为0x004FFA50 0x004FFA51 0x004FFA52 0x004FFA53

1.3 运行中通过指针修改内存值

在程序运行时,我们可以通过调试器修改内存中值。

那么我们是否可以代码方式在程序运行时修改内存,应该也是可以的。这样做的前提时你需要知道类在内存中占用多少字节?
类中包含3个int类型数据,但是类除了数据之外,还会有对齐值等影响类在内存中占用的字节数,此处不要求掌握。
一种简单的方法,使用int nSize = sizeof(clock);来编译时查看变量等在内存中占用的字节数。
对代码修改后可以看到,clock对象占用字节数为12,且m_nHour所在地址为首地址。

突破访问权限的方法:

//如何突破类的限制访问类的成员变量?常规语法不可以,可以通过指针的方式进行访问
//左侧含义,&clock取对象地址,(int*)&clock将地址强制准换为int指针,*(int*)&clock取指针下的内容*(int*)&clock = 111;

运行结果如下:对象clock中的私有成员变量在程序运行时改变

2. 利用函数指针在C语言中模拟类的封装

此处另外介绍一个小的知识点,我们通过C语言的方式,对手表进行封装,利用C语言模拟类的封装。C语言中结构体中是不可以增加行为的,但是我们又想将函数放入其中,如果放不了函数,我们可以将函数当做一种数据放入结构体中,数据即一种函数指针的方式

(1) 函数指针的定义方式: typedef void((*PFN_SetHour)(int n));
(2) 使用真实的函数地址给函数指针赋值方法: c1.pfnSetHour = SetHour;
(3) 函数指针的调用: c1.pfnSetHour(1);
(4) 为了修改对象中的变量的值将其对象的指针传入函数: void SetHour(struct taglock* c1,int n) {c1->nHour = n;}
(5) 修改结构体的变量值的方法: c1.pfnSetHour(&c1,1);

C++中编译器已经有了c1对象,相当于少传了一个&c1指针。

C语言中封装方法如下:

//封装:
#include <iostream>//定义函数指针,相当于变量,需要赋值
typedef void((*PFN_SetHour)(int n));
//C语言模拟类的封装
struct taglock {int nHour;int nMinute;int n_Second;PFN_SetHour pfnSetHour;
};//通过struct taglock* c1传入需要修改的目标,与结构体关联
void SetHour(struct taglock* c1,int n) {c1->nHour = n;}//调用函数
main()
{struct taglock c1;
c1.pfnSetHour = SetHour;
//类似于类中成员函数的调用
c1.pfnSetHour(&c1,1);
}

3.视频学习地址:C++57个入门知识点_17 类的访问权限及C语言模拟类的封装

C++57个入门知识点_17 类的访问权限及C语言模拟类的封装(类的私有权限突破方法:编译期进行权限检查,运行期通过指针修改类的私有成员变量;利用函数指针对结构体中成员变量进行修改;CPU大小尾排列)相关推荐

  1. C语言中利用宏,实现一个整数的奇数位和偶数位交换,以及计算结构体中某变量相对于首地址的偏移

    C语言中的自定义宏 自定义宏,令其实现所需功能 1.写一个宏,可以将一个整数字的奇数位和偶数位交换. 2.写一个宏,计算结构体中某变量相对于首地址的偏移. 具体思路1: 首先取出当前数的奇数部分和偶数 ...

  2. 【C语言】宏offsetof的模拟实现 (计算结构体中某变量相对于首地址的偏移)

    首先我们应该特别留意 : offsetof 是一个宏,并非是一个函数 ! 宏offsetof的介绍 : 参数:第一个是结构体类型名称,第二个是结构体成员名 返回类型:size_t无符号整形 引用的头文 ...

  3. 修改结构体中成员的值

    #include <iostream> using namespace std; struct student {     char name[10];     float grade; ...

  4. 计算机中的变量和函数是什么意思,计算机中的变量和函数是什么意思?

    2019-03-13 回答 if 全部显示 全部隐藏 根据对指定的条件计算结果为true或false,返回不同的结果. 可以使用if对数值和公式执行条件检测. 语法 if(logical_test,v ...

  5. c语言的结构体能存放函数吗,在C语言结构体中添加成员函数

    我们在使用C语言的结构体时,经常都是只定义几个成员变量,而学过面向对象的人应该知道,我们定义类时,不只是定义了成员变量,还定义了成员方法,而类的结构和结构体非常的相似,所以,为什么不想想如何在C语言结 ...

  6. 在php中函数名称区分大小写吗,PHP中的变量名,函数名,类名是区分大小写的吗...

    在javascript中关于变量与函数的提升 在javascript中关于变量与函数的提升 一.简介 在javascript中声明变量与函数的执行步骤: 1.先预解析变量或函数声明代码,会把用var声 ...

  7. 如何利用函数指针在c语言中实现面向对象编程

    面向过程编程 c语言,是一种函数流语言,看他的代码,大部分是call1(data), call2(data)类似的代码.所以他的主体思想是函数,把数据丢进去给函数执行. 面向对象编程 java语言,和 ...

  8. 结构体类型的变量的初始化

    上一篇文章讲了结构体的定义以及结构体类型变量的定义,这一篇我们来讲一下结构体变量的初始化.结构体变量的初始化既可以在定义变量的时候初始化,也可以定义完变量后,在单独给变量的成员变量赋值. 先定义一个结 ...

  9. C语言 泛型链表 如何计算(结构体中各元素)相对内存地址?(字节对齐,结构体对齐)offsetof()函数 ( (struct X*)0 ) -> Y)语法(匿名结构体)

    示例: typedef struct _user {char name[20];char sex[20];int age;struct list_head mylist;//自定义结构体里保存双向循环 ...

最新文章

  1. RxJava 过滤操作符 take 与 takeLast
  2. PHP获取毫秒时间戳,利用microtime()函数
  3. python培训中心-想学python,上海Python培训中心哪个好?
  4. C语言选择排序(解析)
  5. 轻芒王俊煜:我是如何设计信息流的?
  6. 前端技术以及工程化工具
  7. java 实例域_Java实例域初始化方法及顺序
  8. ggplot2 | 注释函数
  9. 生产力系统的四类要素
  10. spring mvc controller间跳转 重定向 传参 (转)
  11. 免费下载网易云音乐付费歌曲及下架歌曲
  12. java基础练习实例_java基础练习题百度云.doc
  13. 二元函数求导公式_基本函数求导公式
  14. 为什么webview中网页字体大小跟样式设置的不同?
  15. 安焦删除贴 牛人纷纷出现(2)
  16. ​WebStorm 超好用的10款插件,效率提升了好多!
  17. 文献阅读-区块链发展现状与展望
  18. Codeforces Round #715 (Div. 2) A. Average Height
  19. 网络安全(刘建伟/毛剑版本)重点整理/复试/期末
  20. 面试高频算法题补充系列:如何判断一个点是否在三角形内?

热门文章

  1. 理论一、MSCKF算法简介
  2. ALSA音频编程常用参数详细说明
  3. 洛谷P3964 [TJOI2013]松鼠聚会 切比雪夫距离转曼哈顿距离
  4. jQuery无刷新上传学习心得
  5. 嘉立创EDA专业版--PCB器件重叠如何选中
  6. 未来刷脸支付是能够占据市场很多的份额
  7. 怎么在html中居中添加视频,HTML中的居中方法
  8. 【经典密码学】Rot5/Rot13/Rot18/Rot47----python
  9. Echarts 地图隐藏右下角 “南海诸岛” 的方法
  10. 【解决方案】物流行业如何通过国标GB28181协议国标平台EasyGBS建立车载视频可视化监控系统?