C/C++语言基础--C++类数据、静态与非静态、常成员、友员、成员变量与函数指针等相关知识点

本专栏目的

  • 更新C/C++的基础语法,包括C++的一些新特性

前言

  • 通过前面几节,我们介绍了C++的类与对象、构造与析构函数、拷贝等相关知识,这一篇将详细介绍了C++的成员变量相关的知识点与扩展
  • C语言后面也会继续更新知识点,如内联汇编;
  • 本人现在正在写一个C语言的图书管理系统,1000多行代码,包含之前所学的所有知识点,包括链表和顺序表等数据结构,请大家耐心等待!!预计国庆前写完更新。

文章目录

    • 类中数据与函数储存
    • 静态(static)成员
      • 静态成员变量
      • 静态成员函数
      • 普通成员函数的内部处理
      • pthis对象指针与this指针
    • 常(const)成员
      • const成员变量
      • const成员函数
        • mutable
      • 注意
    • 友元(了解即可)
      • 友元函数
      • 友元类
      • 注意
    • 成员指针
      • 成员变量指针
        • 非静态成员变量指针
        • 静态成员变量指针
      • 成员函数指针(类)
        • 非静态成员函数指针

类中数据与函数储存

C++的数据主要是对类的抽象,类是面向对象的抽象,在C++面向对象程序设计中,主要有两部分:

  • C++语言中构造、析构函数、虚函数、继承、多态等是是支持面向对象程序设计直接体现
  • C++中这个底层机制为上面这一点做支撑

故从以上点来看类数据储存

  • C++中的类从面向对象理论出发,将变量(属性)和函数(方法)集中定义在一起,用于描述现实世界中的类。
  • 从计算机的角度,程序依然由数据段和代码段构成。

接下来思考下面程序运行的结果?,你感觉他会输出的值是多少呢?

class C1
{
public:int i;int j;int k;static int number;   // 静态
};class C2
{
public:int i;int j;int k;int getK(){return k;}    // 成员函数void setK(int nk){i = nk;}   // 成员函数
};void test()
{cout<<"c1:%d "<<sizeof(C1)<<endl;cout<<"c2:%d "<<sizeof(C2)<<endl;
}

输出结果:

c1:%d 12
c2:%d 12

原因

  • 成员变量
    • 普通成员变量:存储在对象中(对象存储位置由创建位置决定),与struct对象有相同的内存布局和字节对齐方式(尤其要注意对其方式)
    • 静态成员变量:存储在静态变量区(全局区),这个下一节也将会详细讲解
  • 成员函数
    • 存储在代码段中,而对象储存位置由创建的位置决定。

问题出来了:很多对象共用一块代码?代码是如何区分具体对象的那?

换句话说:int getK() { return k; },代码是如何区分,具体obj1、obj2、obj3对象的k值?

静态(static)成员

C++是对类的抽象,故在C++中类中静态成员分为静态成员变量静态成员函数,创建静态成员变量静态成员函数只需要用关键之static

静态成员在内存中存储在全局区,声明周期是从程序开始到结束,故其他成员可以贡献其资源。

静态成员变量

  • static 成员变量和普通 static 变量一样,都在内存分区中的全局数据区分配内存,到程序结束时才释放,也就是他不占用类的内存空间(类的生命周期是创建到类的销毁,而销毁可能是超出作用域,也可能手动释放)

  • 静态成员变量必须在类的内部申明,在类的外部定义,除非是使用内联,因为静态成员变量不属于对象,他在全局区,在类或者结构体中只是声明 ,后面必须要定义

class W
{static int s_cnt;			//类的内部声明inline static int s_num;	//C++17 可以直接内联,就不需要在类的外部定义了
};
int W::s_cnt = 0;		//类的外部定义
  • 访问权限:既可以使用对象访问,也可以使用类名访问

在这里插入图片描述

静态成员函数

  • 在类中,static 除了可以声明静态成员变量,还可以声明静态成员函数。
  • 使用权限:普通成员函数可以访问所有成员(静态和非静态都可以),静态成员函数只能访问静态成员

比如说,我们要通过函数获取学生总人数(m_classSize),有两种方法:

  • 定义普通成员函数:可以访问静态成员,但是这个函数只对静态成员进行操作,加上 static 语义更加明确。
  • 定义静态成员函数:在函数前面加上static,可以声明为静态函数

静态成员函数调用方式,有两种:

  • 和普通成员函数一样,通过对象去调用:

  • Student stu;
    stu.classSize();
    
  • 不定义对象,直接通过类名::函数名去调用

  • Student::classSize();
    

思考:为什么静态成员函数不能调用类的非静态成员?

在类的定义中,变量内存分配和函数是不同的,类的内存大小=类的成员变量内存大小,而成员函数是在创建对象的时候要调用的时候创建的,这样有利于节约内存,而静态成员函数存储在全局区,一定义就创建出来了,如果在静态成员函数中调用类的成员函数的话,就会发现那个成员函数根本不存在,总的来说就是:

  • 上下文环境不同
  • this指向不同

普通成员函数的内部处理

左边为C++代码,右边为C语言代码

在这里插入图片描述

其实把C++的类改为C语言,只需要用结构体+函数,然后通过传对象的指针,在函数里面访问即可!(右边的代码)

pthis对象指针与this指针

通过C语言的方式,对成员变量进行修改、赋值…………操作,用C风格方式,可能的采用指针的方法,但是这样也有一个问题,如下:

在这里插入图片描述
上面问题就是,pthis这个指针指向修改了,并不是指向原有的位置。

那么有没有什么办法可以让pthis指针在函数里面不能被修改呢?

  • 可以给pthis指针加上const属性,让它不能被改变指向
    在这里插入图片描述

而这个加上const的pthis指针,就是C++的this指针。

注意:

  • this 是 C++ 中的一个关键字,也是一个 const 指针,它指向当前对象,在类的内部可以通过它可以访问当前对象的**所有成员*,如下是他的使用操作
class Stu
{
public:Stu(int age, char* name){this->age = age;}
private:int age;
}
  • 以上发现,如果函数中形参和类的属性名相同,可以通过this解决。

常(const)成员

在类中,如果你不希望某些数据被修改,可以使用const关键字加以限定。const 可以用来修饰成员变量和成员函数的关键字

const成员变量

const 成员变量的用法和普通 const 变量的用法相似,只需要在声明时加上 const 关键字。

  • 初始化 const 成员变量只有一种方法,就是通过构造函数的初始化列表
class Test
{
public:Test() {};  // 报错:error C2789:“Test::a”:必须初始化常量限定类型的对象const int m_a;
}
  • 必须通过构造函数的初始化列表初始化,初始化之后不允许赋值。(但是初始化列表可以)
class Test
{
public:Test(int a): m_a(8){m_a = 2;  // error C2166:左俏指定 const 对象}const int m_a;
}// 注意:这种方法不行
class Test
{
public:Test(int a){m_a = a;   // 会报错}
public:const int m_a;
};

const成员函数

const 成员函数可以使用类中的所有成员变量,但是不能在函数里面修改它们的值,通过const 成员函数也称为常成员函数。

但要注意,类中的常成员函数中的const放的位置有点独特,放在函数后面,如下:

class Text
{
public:void fix() const   // 放到这里{m_age = 2;   // 会报错}
private:int m_age;
}
mutable

在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中,如上面程序可以做修改:

class Text
{
public:void fix() const   // 放到这里{m_age = 2;   // 这样就不会报错了}
private:mutable int m_age;
}

注意

  • 常成员函数可以访问任何成员
  • 常对象只能访问常函数,这个很容易忽略,但是编译器编译的时候,我们也很容易发现错误更改。

友元(了解即可)

在C++中,私有成员只能在类的成员函数内部访问,如果想在别处访问对象的私有成员,只能通过类提供的接口间接地进行,所以C++引入友元的概念,使得被定义为友元的函数即使在外部,也能访问类中的私有成员。

友元函数

  • 全局函数作为友元函数
class GirlFriend
{//在public之前friend void stage(GirlFriend& girl);
private:int data;
public:GirlFriend(int data):data(data){}
};void stage(GirlFriend& girl)
{GirlFriend t(33);cout << "data: " << girl.data<<" " << t.data;
}int main()
{GirlFriend g(2);stage(g);return 0;
}

我们在GirlFriend类中把stage函数声明为了友元函数,这样子就可以在stage函数中访问GirlFriend类的私有成员了~

  • 成员函数作为友元函数
class GirlFriend;       //必须提前声明
class BoyFriend
{
public:BoyFriend() = default;void kissGirlFriend(GirlFriend* girlFriend);
};class GirlFriend
{friend void stage(GirlFriend& girl);friend void BoyFriend::kissGirlFriend(GirlFriend* girlFriend);
private:int data;
public:GirlFriend(int data):data(data){}
};// 实现顺序一一定要注意
void BoyFriend::kissGirlFriend(GirlFriend* girlFriend)   //必须在类外实现
{cout << "kiss kiss " << girlFriend->data << endl;
}int main()
{GirlFriend g(2);BoyFriend boy;boy.kissGirlFriend(&g);return 0;
}

一个类的成员函数作为另一个类的友元函数的时候,这个成员函数必须在类外实现,而且是必须在作为友元的类之后实现。

  • 类做友元

  • 注意点

    • 不能把别的类的私有函数定义为友元。
    • 一个函数可以被多个类声明为友元函数,这样就可以访问多个类中的 private 成员
    • 尽量不要用,故了解即可,忘了在查

友元类

//在哪一个类中声明为友元,则本类的**成员函数**就可以访问那一个类的私有成员
class BoyFriendclass GirlFriend
{friend class BoyFriend;
private:int data;
public:GirlFriend(int data):data(data){}
};class BoyFriend
{
private:
public:void bedExercise(GirlFriend* girl){cout << __FUNCTION__ << " " << girl->data;}
};int main()
{GirlFriend g(234);BoyFriend().bedExercise(&g);return 0;
}

GirlFriend类中,把BoyFriend类声明为了友元类,此时在BoyFriend类中,就可以随心所欲的访问 GirlFriend类的私有成员了!

注意

友元函数有优点也有缺点,用好了是神器,用坏了是毁灭!

**优点:**能够提高效率,表达简单、清晰

缺点: 友元函数破环了类的封装性,尽量使用成员函数,除非不得已的情况下才使用友元函数

建议:常中用的也不多,用到忘了在查也行

成员指针

下面内容,了解即可,需要实际情况学习,忘了现查也行。

成员变量指针

非静态成员变量指针

定义成员变量指针:

 int A::*p = &A::num;   // 注意:*p是定义的,在A类中没用被定义

通过成员变量指针访问成员变量:

A a(22);
cout<<" "<<a.*p;   // ** 必须 **通过对象去访问
静态成员变量指针

定义静态成员变量指针:

int *p = &A::static_number;

可以通过对象访问

A a(22);
cout<<" "<<a.*p;
// 也可以,直接输出
cout << *p << endl;  

成员函数指针(类)

非静态成员函数指针

定义成员函数指针:

void (A:: * pshow)() = &A::show;           //对于成员函数来说必须取地址
//A:: show()     这是类的真正原型,在类中只是省略了

通过成员函数指针调用成员函数

//在类外调用 , 必须通过对象调用
(a.*pshow)();              //必须先实例化对象
//在类内调用
(this->*pshow)();

静态成员函数指针

定义静态成员函数指针:(存在全局区里)

void (* pstatic_show)() = &A::static_show;

不可以通过对象访问

cout<<" "<<(*pstatic_show());

也可以直接访问

cout<<" "<<pstatic_show();
  • 定义静态成员指针时候,左边都不加 对象:: ,只有定义非静态成员才会加 (A:: *show)() 。但是右边一样,都要加&

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

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

相关文章

Python | Leetcode Python题解之第423题从英文中重建数字

题目&#xff1a; 题解&#xff1a; class Solution:def originalDigits(self, s: str) -> str:c Counter(s)cnt [0] * 10cnt[0] c["z"]cnt[2] c["w"]cnt[4] c["u"]cnt[6] c["x"]cnt[8] c["g"]cnt[3] c["h…

初探shell与bash使用指南

文章目录 一、shell二、bash第一步、新建脚本第二步、添加权限第三步、执行bash脚本 在日常开发中&#xff0c;经常使用到Linux服务器相关知识&#xff0c;输入命令获取想要的结果&#xff0c;本篇介绍shell 与 bash的相关知识。 一、shell 是命令行解释器&#xff0c;接收用户…

C盘空间不足--WizTree(管理空间)

WizTree&#xff1a;高效的磁盘空间分析工具 在日常使用电脑的过程中&#xff0c;磁盘空间的管理常常成为一个棘手的问题。随着文件的不断增加&#xff0c;我们的硬盘空间逐渐被占满&#xff0c;而这些文件中有很多其实并不重要。为了帮助用户更好地管理磁盘空间&#xff0c;Wi…

【AI学习】Lilian Weng:What are Diffusion Models?

读OpenAI 的 Lilian Weng博客《What are Diffusion Models?》 文章链接:https://lilianweng.github.io/posts/2021-07-11-diffusion-models/ 通过浏览器的在线翻译&#xff0c;直接截图了。翻译的有些问题&#xff0c;但是基本能大概看明白了。 我只是个人的记录&#xff0c;…

Redis的三种持久化方法详解

Redis持久化机制详解 | JavaGuide Redis 不同于 Memcached 的很重要一点就是&#xff0c;Redis 支持持久化&#xff0c;而且支持 3 种持久化方式: 快照&#xff08;snapshotting&#xff0c;RDB&#xff09;只追加文件&#xff08;append-only file, AOF&#xff09;RDB 和 A…

本地生活商城开发搭建 同城O2O线上线下推广

同城本地化商城目前如火如荼&#xff0c;不少朋友咨询本地生活同城平台怎么开发&#xff0c;今天商淘云与大家分享同城O2O线上商城的设计和开发。 本地生活商城一般会涉及到区域以及频道类&#xff0c;一般下单需要支持用户定位、商家定位&#xff0c;这样利于用户可以快速找到…

51单片机快速入门之按键应用拓展

51单片机快速入门之按键应用拓展 LED的点动控制: 循环检测,当key 为0 时 led 亮 反之为熄灭 while(1){ if(key!1) { led0; }else { led1; } } LED的锁定控制: 当按钮按下,led取反值 while(1) { if(key!1) { led!led; } } LED的4路抢答控制: bz默认为0 !bz 取反值,循环启动…

C++系列-模版

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 非类型模版参数 模板参数分类型模板参数与非类型模板参数 类型形参即&#xff1a;出现在模板参数列表&#xff0c;跟在class或者typename之类的参数类型名称 非类型形参即&am…

SpringBoot 数据库表结构文档生成

官方地址&#xff1a;https://github.com/pingfangushi/screw screw 螺丝钉&#xff0c;支持以下数据库 MySQL MariaDB TIDB Oracle SqlServer PostgreSQL Cache DB&#xff08;2016&#xff09; 生产文档支持 html word markdown 开始 添加依赖 <!-- 螺丝钉 --><…

软件测试技术之 GPU 单元测试是什么!

1 背景 测试是开发的一个非常重要的方面&#xff0c;可以在很大程度上决定一个应用程序的命运。良好的测试可以在早期捕获导致应用程序崩溃的问题&#xff0c;但较差的测试往往总是导致故障和停机。 单元测试用于测试各个代码组件&#xff0c;并确保代码按照预期的方式工作。单…

三维重建的几何评价指标

1.三维重建的几何评价指标 1.1 Chamfer Distance Geometry quality (1) Chamfer Distance&#xff08;CD&#xff09; CD衡量两组点云之间的几何差异&#xff0c;距离越小越好。 CD是一种用于衡量两个点云之间相似度的常用几何评价指标。它计算一个点云中每个点到另一个点云的…

seL4 Threads(四)

官网链接: Threads Threads 这篇教程主要是使用seL4中的threads。 TCB Thread Control Blocks seL4提供了线程代表执行的上下文以及管理处理器时间。seL4中的线程是通过线程控制块对象&#xff08;TCB&#xff09;实现的&#xff0c;每个内核线程都有一个线程控制块。 线程…

Web3技术在元宇宙中的应用:从区块链到智能合约

随着元宇宙的兴起&#xff0c;Web3技术正逐渐成为其基础&#xff0c;推动着数字空间的重塑。元宇宙不仅是一个虚拟世界&#xff0c;它还代表着一个由去中心化技术驱动的新生态系统。在这个系统中&#xff0c;区块链和智能合约发挥着至关重要的作用&#xff0c;为用户提供安全、…

Vue | watch监听

Vue | watch监听 在Vue.js的世界里&#xff0c;watch监听器是一个强大且灵活的工具&#xff0c;它允许我们在数据变化时执行特定的逻辑。本文将深入探讨watch的出现背景、使用方法、应用场景、源码原理以及扩展技巧&#xff0c;旨在帮助读者全面掌握这一重要特性。 文章目录 Vu…

TMStarget学习——T1 Segmentation数据处理及解bug

最新学习季公俊老师的神器 TMStarget 的第一个模块基于结构像的靶区计算T1 segmentation。下面上步骤&#xff1a; (1)在github 上下载 TMStarget https://github.com/jigongjun/Neuroimaging-and-Neuromodulation (2)按照要求下载依赖工具软件AFQ、vistasoft、SPM12 &#…

笔试编程-百战成神——Day02

1.简写单词 题目来源&#xff1a; 简写单词——牛客网 测试用例 算法原理 本题的主要难点就是如何识别每一个单词并且返回其首字母大写&#xff0c;最终组成一个新的字符串后输出&#xff0c;这里我们使用while(cin>>str)就可以解决&#xff0c;直接忽略每一个空格直接…

20240926 每日AI必读资讯

一个开源的自托管 AI 入门工具包 - 此工具包利用Docker Compose模板&#xff0c;包含多种本地AI工具并提供AI工作流模板和网络配置&#xff0c;简化了本地AI工具的安装和使用。 安装它将拥有&#xff1a; • 一个拥有 400 多个 AI 组件和集成的低代码平台 • Ollama&#xf…

基于stm32物联网身体健康检测系统

在当今社会&#xff0c;由于经济的发展带来了人们生活水平不断提高&#xff0c;但是人们的健康问题却越来越突出了&#xff0c;各种各样的亚健康随处可在&#xff0c;失眠、抑郁、焦虑症&#xff0c;高血压、高血糖等等侵袭着人们的健康&#xff0c;人们对健康的关注达到了一个…

单细胞Scanpy流程学习和整理(单样本10X数据读取/过滤/降维/聚类)

打算仔细学习一下基于python的单细胞相关分析框架hhh 新手上路写的很繁琐&#xff0c;多多包涵&#xff0c;本次用的IDE是Visual studio code。 流程来自Scanpy官网(Preprocessing and clustering 3k PBMCs (legacy workflow))&#xff1a; https://scanpy.readthedocs.io/e…

01【MATLAB】最小二乘系统辨识

目录 1.系统辨识的定义及其分类 1.1 系统辨识的定义 1.2 系统辨识的分类 2.参数模型 3.系统辨识的步骤 一、最小二乘法&#xff08;Least Squares Method&#xff09;一般步骤 二、LSM原理及应用 三、LSM在控制系统建模中的应用 1.系统辨识的定义及其分类 1.1 系统辨识的…