C++的面向对象学习(5):对象的重要特性:对象的成员变量和成员函数深入研究

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 一、static修饰的静态成员:与类本身关联,不依赖于任何对象。
    • ①静态成员变量:
    • ②静态成员函数:
      • (1)类内声明静态成员变量,类外赋值初始化静态成员变量。
      • (2)要操作和访问这个静态成员变量,**既可以通过常规的实例化对象去访问**,也**可以通过类名+::作用域去访问**。两个不同的实例化对象,共享的是同一个静态成员变量。
      • (3)关于访问权限:公开的静态成员变量可以在主函数里访问操作,那么私有的呢?
      • (4)静态的成员函数只能访问静态成员变量,不能访问其他成员变量。
      • (5)静态成员变量和静态成员函数的使用场景:
  • 二、类的成员变量和成员函数分开存储
    • 问题①:实例化一个对象,他到底占用多大的内存空间呢?
      • (1)一个空类的内存多大?—— 一个字节
      • (2)类中有一个整形变量,内存多大?——四个字节
      • (3)类中有一个整形和一个静态整形变量,内存多大?——四个字节
      • (4)类中有一个整形、一个静态整形、一个非静态成员函数,内存多大?——四个字节
      • (5)类中有一个整形、一个静态整形、一个非静态成员函数、一个静态成员函数,内存多大?——四个字节
  • 三、this指针:成员函数存储在代码段中,但在调用时会传递一个指向当前对象的指针(this指针)作为隐含参数。
    • 1.问题的提出:既然成员函数不属于对象,那怎么区分哪个对象调用的自己呢?
    • 2.回答:每个对象都可以调用类的成员函数,但是在成员函数内部,可以通过特殊的指针 this 来区分是哪个对象调用了自己。
    • 3.this指针的特点
    • 4.this指针的用途
      • ①解决函数传参与成员变量名相同导致冲突的问题。
      • ②成员函数返回对象本身,使用 return *this语句,从而支持链式调用
  • 四、const修饰的常成员:
    • ①常成员变量:声明后其值无法被修改
    • ②常函数:用const修饰成员函数
    • ③常对象:用const修饰对象
  • 五、友元:允许一个类或函数访问另一个类的私有成员
    • 1.一个全局函数做一个类的友元
    • 2.一个类做另一个类的友元
    • 3.一个类的成员函数做另一个类的友元
    • 4.总结:目前如果要访问类的私有成员变量,有哪些方法?

一、static修饰的静态成员:与类本身关联,不依赖于任何对象。

①静态成员变量:

所有实例化的对象都共享同一份数据。
在编译阶段就会分配内存,而不是实例化对象后才分配。
静态成员变量一般在类里面声明,而在类外进行赋值初始化。
静态成员变量可以通过类名+作用域解析运算符 :: 来访问,而不需要创建类的对象。

②静态成员函数:

所有实例化的对象共享同一个函数。
静态成员函数是与类本身相关联的函数,它们不依赖于类的任何对象。
静态成员函数可以通过类名+作用域解析运算符 :: 来调用,而不需要创建类的对象。
静态成员函数只能访问静态成员变量和其他静态成员函数,不能直接访问非静态成员变量和非静态成员函数。

这里主要是注意以下这些问题:

(1)类内声明静态成员变量,类外赋值初始化静态成员变量。

class Person {
public:
	int age;
	string name;

	static int height;//身高
	
	int getHeight() {
		return height;
	}
};

我们声明了一个公开的静态成员变量height,就需要在类外面对其赋值初始化。

int Person::height = 0;//在类外部先赋值初始化

(2)要操作和访问这个静态成员变量,既可以通过常规的实例化对象去访问,也可以通过类名+::作用域去访问。两个不同的实例化对象,共享的是同一个静态成员变量。

int main() {
	Person p(18, "小明", "华为mate60", 5999);
	Person p2(19, "小李", "华为mate60pro", 7999);
	
	Person::height = 150;//第一次修改身高
	p.height = 160;//第二次修改
	p2.height = 180;//第三次修改
	cout << Person::height << endl;
	system("pause");
	return 0;
}

(3)关于访问权限:公开的静态成员变量可以在主函数里访问操作,那么私有的呢?

通过提供一个公有的静态成员函数来间接初始化私有静态成员变量。这个静态成员函数可以在类的内部访问和修改私有静态成员变量,并在需要的时候进行初始化。

class Person {
private:
    static int weight;

public:
    static int height;
    
    void setWeight(int a) {
        weight = a;
    }

    int getWeight() {
        return weight;
    }
};

int Person::height = 0;
int Person::weight = 0;

(4)静态的成员函数只能访问静态成员变量,不能访问其他成员变量。

在这里插入图片描述
age这是一个普通变量,就不能被静态函数访问。
原因是:我们可能会将一个类实例化很多个对象,静态成员变量被共享,所以编译器觉得你可以通过静态函数随便修改。但是,每个对象的普通成员变量是不共享的,不能通过一个公用的静态函数去修改,编译器会分辨不清你到底要修改的是哪个对象的成员变量

(5)静态成员变量和静态成员函数的使用场景:

1.静态成员变量适用于表示与类相关的全局信息,例如记录类的实例个数、保存全局配置等。
2.静态成员函数适用于不依赖于类的任何对象,但仍然与类相关的操作,例如提供工具函数、计算与类相关的统计信息等。

二、类的成员变量和成员函数分开存储

非静态成员变量存储在每个类的对象中,每个对象都有自己的成员变量副本。
非静态成员函数存储在类的代码段中,它们不占用对象的内存空间。

问题①:实例化一个对象,他到底占用多大的内存空间呢?

(1)一个空类的内存多大?—— 一个字节

	Car c1;
	cout << sizeof(c1) << endl;

答案:一个字节。一个空类至少会占用一个字节的内存空间,以确保每个对象在内存中有独一无二的地址。这是因为每个对象在内存中必须具有唯一的地址,以便能够区分不同的对象

(2)类中有一个整形变量,内存多大?——四个字节

答案:把类看作是一个结构体,那么其实这时实例化对象后,这个对象的大小就是4字节。

(3)类中有一个整形和一个静态整形变量,内存多大?——四个字节

答:因为静态变量不属于对象的属性,它只与类关联,所以不属于类的对象,所以实例化的对象的大小只是那个普通的整型变量speed的大小。

class Car {
private:
	int speed;
	static int colour;
};
int main() {
	Car c1;
	cout << sizeof(c1) << endl;
	return 0;
}

(4)类中有一个整形、一个静态整形、一个非静态成员函数,内存多大?——四个字节

答:非静态成员函数同样不属于类的对象,它存储在类的代码段。当调用成员函数时,会将对象的地址作为隐含参数传递给函数,以便函数可以访问对象的成员变量。

class Car {
private:
	int speed;
	static int colour;

public:
	void func() {
		cout << "666" << endl;
	}
};

(5)类中有一个整形、一个静态整形、一个非静态成员函数、一个静态成员函数,内存多大?——四个字节

答:静态成员函数同样不属于类的对象

class Car {
private:
	int speed;
	static int colour;

public:
	void func() {
		cout << "666" << endl;
	}
	static void add() {
		cout << "777" << endl;
	}
};

类实例化一个对象后,只有类的非静态成员变量属于该对象,占据该对象的内存空间。其他的变量和函数均不属于该对象。

总结:一个对象的内存空间主要由其非静态成员变量决定,而其他的静态成员变量和成员函数不占据对象的内存空间。注意一个空类的对象占1个字节。

三、this指针:成员函数存储在代码段中,但在调用时会传递一个指向当前对象的指针(this指针)作为隐含参数。

1.问题的提出:既然成员函数不属于对象,那怎么区分哪个对象调用的自己呢?

2.回答:每个对象都可以调用类的成员函数,但是在成员函数内部,可以通过特殊的指针 this 来区分是哪个对象调用了自己。

3.this指针的特点

①this指针指向当前被调用的成员函数所属的对象。比如目前是p1在调用函数,this指针就指向p1,然后p22调用这个函数,this指针就指向p2。
②this指针是隐含在成员函数内部的,不需要定义,直接使用。

4.this指针的用途

①解决函数传参与成员变量名相同导致冲突的问题。

在这里插入图片描述
这个样子,编译器就认为三个speed都是一个东西。
用this指针修改:

	void func(int speed) {
		//speed = speed;
		this->speed = speed;
	}

int main() {
	Car c1;
	c1.func(180);
	system("pause");
	return 0;
}

主程序调用c1的func函数时,this指针指向的就是当前的对象c1,于是就有类似结构体指针的操作,用->运算符代表对象c1内部的具体成员变量
在这里插入图片描述

②成员函数返回对象本身,使用 return *this语句,从而支持链式调用

#include <iostream>

class MyClass {
private:
    int value;

public:
    MyClass(int val) : value(val) {}

    MyClass& setValue(int val) {//返回一个指向 MyClass 类型对象的引用
        value = val;
        return *this;
    }

    MyClass& add(int num) {
        value += num;
        return *this;
    }

    void printValue() {
        cout << "Value: " << value << endl;
    }
};

int main() {
    MyClass obj(5);
    obj.setValue(10).add(3).printValue();  // 链式调用

    return 0;
}

MyClass 类有三个成员函数:setValue()、add() 和 printValue()。setValue() 函数用于设置对象的值,add() 函数用于将给定的数值添加到对象的值上,printValue() 函数用于打印对象的值。
通过返回引用,我们可以在链式调用中持续操作同一个对象,而不是每次调用都返回一个新的对象副本。

四、const修饰的常成员:

①常成员变量:声明后其值无法被修改

常成员变量必须在类的构造函数中进行初始化,一旦被初始化,就不能再修改它们的值。
常成员变量的值在整个对象的生命周期中都保持不变。

②常函数:用const修饰成员函数

1.常函数内部不可以修改成员属性。
2.若加关键字mutable来修饰成员属性,则在常函数中依然可以修改。
在这里插入图片描述

③常对象:用const修饰对象

mutable int colour;//声明其是可变变量

const Car c3;
c3.setColor(5);

需要在常成员函数中修改成员变量的值,可以将成员变量声明为 mutable,这样就可以在常成员函数中修改它们的值了。
需要注意的是,mutable 成员变量可以在常成员函数中被修改,但不能在常量对象上调用非常量成员函数来修改它们的值

即:常对象不能调用普通成员函数,只能调用常函数。 因为普通成员函数可以修改属性。

五、友元:允许一个类或函数访问另一个类的私有成员

什么叫友元?
对于一个类,私有权限的属性就好比卧室,公开权限的属性就好比客厅。

如果我想让类外面的一些特殊的函数或者类可以访问这些私有权限的属性,就需要友元。
关键字:friend

1.一个全局函数做一个类的友元

非常简单。让一个全局函数成为类的友元函数,可以在类的定义中使用 friend 关键字来声明该函数。这样,该全局函数就可以访问类的私有成员。
注意,在类中声明友元函数,随便放,不用管它是私有还是公开。

class HOUSE {

	friend void goodbey(HOUSE hou);//最重要,只需要声明这一句即可。

public:
	string sittingRoom;//客厅

	HOUSE(string a, string b) :sittingRoom(a), bedroom(b) {}
private:
	string bedroom;//卧室

};

void goodbey(HOUSE hou) {

	cout << hou.sittingRoom << endl;//公开成员变量,无论何时全局函数都能访问
	cout << hou.bedroom << endl;//私有成员变量,要在类里面将全局函数声明为友好的,才能访问
}

2.一个类做另一个类的友元

HOUSE 类中声明了一个名为 Visitor 的类作为友元。这意味着 Visitor 类可以访问 HOUSE 类的私有成员 bedroom。
语法也很简单:和全局函数类似,在类中用关键字friend声明那个需要做友元的类即可。

class HOUSE {

	friend void goodbey(HOUSE hou);
	friend class Visitor;
public:
	string sittingRoom;//客厅

	HOUSE(string a, string b) :sittingRoom(a), bedroom(b) {}
private:
	string bedroom;//卧室

};

class Visitor {//一个类作为友元
public:
	void visit(HOUSE& hou) {
		hou.bedroom = "666";
		cout << hou.bedroom << endl;
	}
};

3.一个类的成员函数做另一个类的友元

一个类的成员函数可以被声明为另一个类的友元函数。这意味着该成员函数可以访问友元类的私有成员。
这里理论上代码是这样的:

class HOUSE;

class Watcher {
public:
    void look(HOUSE& hou);
};

class HOUSE {
    friend void goodbey(HOUSE hou);
    friend class Visitor;
    friend void Watcher::look(HOUSE& hou);

public:
    string sittingRoom; // 客厅

    HOUSE(string a, string b) : sittingRoom(a), bedroom(b) {}

private:
    string bedroom; // 卧室
};

void Watcher::look(HOUSE& hou) {
    hou.bedroom = "777";
}

void goodbey(HOUSE hou) {
    cout << hou.sittingRoom << endl;
    cout << hou.bedroom << endl;
}

class Visitor {
public:
    void visit(HOUSE& hou) {
        hou.bedroom = "666";
        cout << hou.bedroom << endl;
    }
};

但是我用VS2022编译会报错,不管怎么修改类的声明与定义的前后顺序都会报错,不知道为什么。这个问题以后遇到再说,反正,目前用前两种方法就行。

4.总结:目前如果要访问类的私有成员变量,有哪些方法?

如果要访问类的私有成员变量,有以下几种方法:

使用公有成员函数:在类中定义公有成员函数,通过这些函数来访问和修改私有成员变量。这种方法可以提供对私有成员变量的控制和封装。

使用友元函数:在类中声明友元函数,使其能够访问类的私有成员变量。友元函数可以是全局函数,也可以是其他类的成员函数。友元函数可以直接访问类的私有成员变量,但会破坏封装性。

使用友元类:在类中声明友元类,使其能够访问类的私有成员变量。友元类的所有成员函数都可以访问类的私有成员变量。友元类可以提供更多的灵活性和控制,但同样会破坏封装性。

需要注意的是,尽量遵循封装的原则,只在必要的情况下使用友元函数或友元类来访问私有成员变量。尽量通过公有接口(公有成员函数)来操作私有成员变量,以保持类的封装性和安全性。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker 编译OpenHarmony 4.0 release

一、背景介绍 1.1、环境配置 编译环境&#xff1a;Ubuntu 20.04OpenHarmony版本&#xff1a;4.0 release平台设备&#xff1a;RK3568 OpenHarmony 3.2更新至OpenHarmony 4.0后&#xff0c;公司服务器无法编译通过&#xff0c;总是在最后几十个文件时报错,错误码4000&#xf…

python+django教学质量评价系统o8x1z

本基于web的在线教学质量评价系统的设计与实现有管理员&#xff0c;教师&#xff0c;督导&#xff0c;学生一共四个角色。管理员功能有个人中心&#xff0c;学生管理&#xff0c;教师管理&#xff0c;督导管理&#xff0c;学生评价管理&#xff0c;课程信息管理&#xff0c;学生…

less 查看文本时,提示may be a binary file.See it anyway?

解决办法 首先使用echo $LESSCHARSET查看less的编码 看情况设置less的编码格式(我的服务器上使用utf-8查看中文) 还要特别注意一下&#xff0c;Linux中存在的文本文件的编码一定要是utf - 8;&#xff08;这一步很关键&#xff09; 例如&#xff1a;要保证windows上传到Linux的…

Centos系统升级gcc版本

自己环境的gcc版本太低&#xff0c;影响使用SAN全家桶进行内存泄露检查 当前环境gcc版本查看 gcc --version 进行升级&#xff1a; 1、安装EPEL存储库 yum install epel-release -y 2、确保系统已经更新到最新版本 yum update -y 3、安装GCC编译器及其相关工具包 yum g…

The Cherno C++笔记 03

目录 Part 07 How the C Linker Works 1.链接 2.编译链接过程中出现的错误 2.1 缺少入口函数 注意:如何区分编译错误还是链接错误 注意&#xff1a;入口点可以自己设置 2.2 找不到自定义函数 2.2.1缺少声明 2.2.2自定义函数与引用函数不一致 2.3 在头文件中放入定义 …

基于kubernetes实现PaaS云平台-rancher

基于Rancher实现kubernetes集群管理 一、Rancher介绍 1.1 Rancher Rancher 是一套容器管理平台&#xff0c;它可以帮助组织在生产环境中轻松快捷的部署和管理容器。Rancher可以轻松地管理各种环境的 Kubernetes&#xff0c;满足IT需求并为 DevOps 团队提供支持。 Rancher 用…

css 设备背景图片 宽高总是不能平铺

宽高总是宽大了 高就挤出去了&#xff1b;高设置了 宽度就变小了&#xff1b;疯掉的节奏。。。。。。 .center-bottom{background: url(/img/newpic/leftbg.png);background-repeat: no-repeat;width: 98%;height: 60%;background-position: center center;background-size: 1…

STM32微控制器在HC-SR501红外感应模块中的能耗优化策略研究

一、 引言 能耗优化是嵌入式系统设计中一个重要的考虑因素&#xff0c;特别是在电池供电的应用中。在使用HC-SR501红外感应模块时&#xff0c;能耗优化策略对于延长电池寿命、提高系统性能至关重要。本文将阐述基于STM32微控制器的HC-SR501红外感应模块能耗优化策略研究。 二、…

Apache Flink 进阶教程(六):Flink 作业执行深度解析

目录 前言 Flink 四层转化流程 Program 到 StreamGraph 的转化 StreamGraph 到 JobGraph 的转化 为什么要为每个 operator 生成 hash 值&#xff1f; 每个 operator 是怎样生成 hash 值的&#xff1f; JobGraph 到 ExexcutionGraph 以及物理执行计划 Flink Job 执行流程…

web架构师编辑器内容-改进字体下拉菜单

前面说到我们可以通过面板配置来更新画布上面的一些属性&#xff0c;如果我们有这样一个需求&#xff1a;在右侧面板配置里面需要查看字体的样式效果我们应该怎么做呢&#xff1f; 我们一开始字体的渲染&#xff1a; const fontFamilyArr [{value: "SimSun","…

parseInt(0.0000005)大于等于5

文章目录 一、前言二、parseInt()的神秘行为三、解决parseInt()的奥秘四、结论五、最后 一、前言 parseInt() 是 JavaScript 的内置函数&#xff0c;用于解析数字字符串中的整数。例如&#xff0c;从数字字符串中解析整数100&#xff1a; const number parseInt(100); numbe…

nodejs+vue+微信小程序+python+PHP医疗机构药品及耗材信息管理系统-计算机毕业设计推荐

为了帮助用户更好的了解和理解程序的开发流程与相关内容&#xff0c;本文将通过六个章节进行内容阐述。 第一章&#xff1a;描述了程序的开发背景&#xff0c;程序运用于现实生活的目的与意义&#xff0c;以及程序文档的结构安排信息&#xff1b; 第二章&#xff1a;描述了程序…

第11章 GUI Page400~402 步骤二 画直线

运行效果&#xff1a; 源代码&#xff1a; /**************************************************************** Name: wxMyPainterApp.h* Purpose: Defines Application Class* Author: yanzhenxi (3065598272qq.com)* Created: 2023-12-21* Copyright: yanzhen…

vue3开发一个todo List

创建新的 Vue 3 项目&#xff1a; 按装vue3的 工具 npm install -g vue/cli创建一个新的 Vue 3 项目&#xff1a; vue create vue3-todolist进入项目目录&#xff1a; cd vue3-todolist代码&#xff1a; 在项目的 src/components 目录下&#xff0c;创建一个新的文件 Todo…

视频美颜SDK开发指南:实现高质量实时美颜效果

下文小编将于大家一同探讨美颜SDK的开发指南&#xff0c;希望开发者们能够获得一定的启发。 一、理解实时美颜的挑战 实时美颜涉及到对视频流进行实时处理&#xff0c;这对计算资源和算法效率提出了严峻的挑战。在开发视频美颜SDK之前&#xff0c;我们需要理解以下几个关键方…

【Amazon 实验②】Amazon WAF功能增强之使用Cloudfront、Lambda@Edge阻挡攻击

文章目录 一、方案介绍二、架构图三、部署方案1. 进入Cloud9 编辑器&#xff0c;新打开一个teminal2. 克隆代码3. 解绑上一个实验中Cloudfront 分配绑定的防火墙4. 使用CDK部署方案5. CDK部署完成6. 关联LambdaEdge函数 四、方案效果 一、方案介绍 采用 LambdaEdge DynamoDB 架…

Web组态可视化编辑器-by组态

演示地址&#xff1a; http://www.by-lot.com http://www.byzt.net web组态可视化编辑器&#xff1a;引领未来可视化编辑的新潮流 随着网络的普及和快速发展&#xff0c;web组态可视化编辑器应运而生&#xff0c;为人们在网络世界中创建和编辑内容提供了更加便捷的操作方式。这…

【ARMv8M Cortex-M33 系列 1 -- SAU 介绍】

文章目录 Cortex-M33 SAU 介绍SAU 的主要功能包括SAU 寄存器配置示例 Cortex-M33 SAU 介绍 在 ARMv8-M 架构中&#xff0c;SAU&#xff08;Security Attribution Unit&#xff09;是安全属性单元&#xff0c;用于配置和管理内存区域的安全属性。SAU 是 ARM TrustZone 技术的一…

大象机器人发布万元级水星Mercury人形机器人产品系列,联结未来,一触即达!

十四五机器人产业发展规划指出机器人的研发、制造、应用是衡量一个国家科技创新和高端制造业水平的重要标志。当前&#xff0c;机器人产业蓬勃发展&#xff0c;正极大改变着人类生产和生活方式&#xff0c;为经济社会发展注入强劲动能。 人形机器人作为机器人产业中重要的一环&…

Chrome浏览器http自动跳https问题

现象&#xff1a; Chrome浏览器访问http页面时有时会自动跳转https&#xff0c;导致一些问题。比如&#xff1a; 开发阶段访问dev环境网址跳https&#xff0c;后端还是http&#xff0c;导致接口跨域。 复现&#xff1a; 先访问http网址&#xff0c;再改成https访问&#xf…
最新文章