浅谈C++|类的成员

2023-09-16 22:40:46

一.类对象作为类成员

类可以作为另一个类的成员

代码: 

#include <iostream>
using namespace std;
class phone {
public:
	string shouji;
	phone(string shouji1) :shouji(shouji1) {
		cout << "phone的构造函数调用" << endl;
	}
	~phone() {
		cout << "phone的析构函数调用" << endl;
	}
};
class person {
public:
	int age;
	string name;
	phone shouji;
	//隐式转换相当于shouji=phone(shouji1)
	person(int a, string name1, string shouji1) :age(a), name(name1), shouji(shouji1) {
		cout << "person的构造函数调用" << endl;
	}
	~person() {
		cout << "person的析构函数调用" << endl;
	}
};
void fun() {
	person p(23, "小明", "苹果");
}
int main() {
	fun();
	return 0;
}

 注意:

创建类时,被包含的类的构造函数先调用,随后外层类的构造函数再调用,析构1的时候正好相反,外部类先析构,内部类再析构。

二.静态成员 

静态成员就是在成员变量前面加上static关键字,称为静态成员。

静态成员分为静态成员变量静态成员函数

2.1静态成员变量

。所有对象共享同一份数据

。在编译阶段分配内存。

类内声明,类外初始化·静态成员函数

 静态成员必须在类外初始化,否则编译器认为只声明,但是没有实际定义,链接发生错误。

代码: 

#include <iostream>
using namespace std;
class person {
public:
	static int age;
};
int person::age = 10;
void fun() {
	person p;
	p.age = 90;
	person p1;
	cout << p1.age << endl;
}
int main() {
	fun();
	return 0;
}

 静态成员变量,不仅可以通过对象访问,也可以通过类名访问。静态成员变量也是有访问权限的。

代码: 

#include <iostream>
using namespace std;
class person {
public:
	static int age;
};
int person::age = 10;
void fun() {
	person p;
	p.age = 90;
	cout << person::age << endl;
}
int main() {
	fun();
	return 0;
}

2.2静态成员函数

。所有对象共享同一个函数

静态成员函数只能访问静态成员变量

代码: 

#include <iostream>
using namespace std;
class person {
public:
	static int age;
	static void fun(int a) {
		age = a;          //只能调用静态成员变量
		cout << "静态函数fun调用" << endl;
	}
};
int person::age = 100;
void dioayong() {
	person p;
	p.fun(99);          //对象调用
	person::fun(66);   //类名调用
	cout << p.age << endl;
}
int main() {
	dioayong();
	return 0;
}

同样,静态成员函数也是可以通过类名来调用,需要注意静态成员函数只能调用静态成员变量。

 三.this指针

3.1成员变量和函数的存储

在C++中,类内的的成员变量和成员函数分开存储

只有非静态成员变量才属于类的对象上

在C++中, 空类也占用一个字节。C++编译器会给每个空对象也分配一个字节空间,是为了区分对象占内存的位置

代码: 

#include <iostream>
using namespace std;
class person {

};
void fun() {
	person p;
	cout<<sizeof(p);
}
int main() {
	fun();
	return 0;
}

 在类中同样具有内存对齐的特性

代码: 

#include <iostream>
using namespace std;
class person {
public:
	int a;
	char b;
};
void fun() {
	person p;
	cout<<sizeof(p);
}
int main() {
	fun();
	return 0;
}

 此外,成员函数和静态成员变量都不存储在类上,也就是只有非静态成员变量存储在类中

代码: 

#include <iostream>
using namespace std;
class person {
public:
	int a;
	static int b;
	void fun() {
		cout << "fun函数调用" << endl;
	}
	static void fun1() {
		cout << "fun1函数调用" << endl;
	}
};
int person::b = 10;
void fun() {
	person p;
	cout<<sizeof(p);
}
int main() {
	fun();
	return 0;
}

 3.2this指针使用

每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码那么问题是:这一块代码是如何区分那个对象调用自己的呢?

C++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象

 注意:

1.this指针是隐含每一个非静态成员函教内的一种指针

2.this指针不需要定义,直接使用即可

this指针的用途: 

·当形参和成员变量同名时,可用this指针来区分同名形参和变量

·在类的非静态成员函数中返回对象本身,可使用return *this

 代码:

#include <iostream>
using namespace std;
class people {
public:
	int age;
	people(int age) {
		this->age = age;
	}
};
void zhixing() {
	people p(10);
	cout << p.age << endl;
}
int main() {
	zhixing();
	return 0;
}

返回自身时,注意要返回引用类型,返回普通值类型时,返回值是本身的副本

#include <iostream>
using namespace std;
class people {
public:
	int age;
	people(int age) {
		this->age = age;
	}
	 people& add(const people& p) {
		this->age += p.age;
		return *this;
	}
};
void zhixing() {
	people p1(10);
	people p2(20);
	p2.add(p1).add(p1).add(p1).add(p1);
	cout << p2.age << endl;
}
int main() {
	zhixing();
	return 0;
}

四.空指针访问成员函数

C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针

代码: 

#include <iostream>
using namespace std;
class person {
public:
	int age;
	void fun1() {
		cout << "fun1调用" << endl;
	}
	void fun2() {
		cout << "fun2调用" << age << endl;
	}

};
void diaoyong() {
	person* p = NULL;
	p->fun1();
	p->age = 10;
	p->fun2();
}
int main() {
	diaoyong();
	return 0;
}

 只能成功调用没有this指针的函数,因为此时this是空指针,含有this的调用

 代码:

#include <iostream>
using namespace std;
class person {
public:
	int age;
	void fun1() {
		cout << "fun1调用" << endl;
	}
	void fun2() {
		if (this == NULL) {
			return;
		}
		cout << "fun2调用" << age << endl;
	}

};
void diaoyong() {
	person* p = NULL;
	p->fun1();
	p->fun2();
}
int main() {
	diaoyong();
	return 0;
}

增加代码的健壮性,判断this指针是空指针的时候,跳出函数。

 五.const修饰成员函数

 常函数:

1.成员函数后加const后我们称为这个函数为常函数。

2.常函数内不可以修改成员属性。

3.成员属性声明时加关键字mutable后,在常函数中依然可以修改。

常对象:

1.声明对象前加const称对象为常对象。

2.常对象只能调用常函数和用mutable修饰的成员变量。

 5.1常函数

this指针本质是指针常量,指针的指向是不可以修改的(person* const this),但是this指针指向地址的值是可以发生改变的。

 常函数const要加在函数参数列表后面

代码: 

#include <iostream>
using namespace std;
class person {
public:
	int age;
	void showage(int m) const{
	//	age = 89; //报错
		m = 100;
		cout << "age=" << age <<" m=" << m << endl;
	}
};
void fun() {
	person p;
	p.age = 10;
	p.showage(7);
}
int main() {
	fun();
	return 0;
}

 此时编译器会报错,此时age在函数内是不可改变的。但是函数传的参数,仍然是可以改变的。

#include <iostream>
using namespace std;
class person {
public:
	mutable int age;
	void showage(int m) const{   //常函数
		age = 89; //报错
		m = 100;
		cout << "age=" << age <<" m=" << m << endl;
	}
};
void fun() {
	person p;
	p.age = 10;
	p.showage(7);
}
int main() {
	fun();
	return 0;
}

成员属性声明时加关键字mutable后,在常函数中依然可以修改。

5.2 常对象

 代码:

#include <iostream>
using namespace std;
class person {
public:
	mutable int age;
	void showage1(int m) const{
		//age = 89; //报错
		m = 100;
		cout << "age=" << age <<" m=" << m << endl;
	}
	void showage2(int m)  {
		age = 89;
		m = 100;
		cout << "age=" << age << " m=" << m << endl;
	}
};
void fun() {
	const person p;
	p.age = 10;      
	p.showage1(7);
	//p.showage2(7);  报错  
}
int main() {
	fun();
	return 0;
}

常对象只能调用常函数和用mutable修饰的成员变量。普通函数和普通成员变量不能调用

 六.友元

友元关键字:friend

友元的三种实现:

1.全局函数做友元

2.类做友元

3.成员函数做友元

6.1全局函数做友元 

 代码:

#include <iostream>
using namespace std;

class home {
friend void func(home& p);
public:
	home(string keting, string woshi, string cuosuo):keting(keting),woshi(woshi),cuosuo(cuosuo) {

	}
	string keting;
private:
	string woshi;
protected:
	string cuosuo;
};

void func(home &p) {
	
	cout << p.keting << ' ' << p.woshi << ' ' << p.cuosuo << endl;
}
void fun() {
	home p("客厅", "卧室", "厕所");
	func(p);
}
int main() {
	fun();
	//cout << p.keting << ' ' << p.woshi << ' ' << p.cuosuo << endl;
	//保护和私有属性的不能访问
	return 0;
}

有元函数不是类的成员函数,但是却又权限调用类的所有成员变量

6.2类做友元 

​​#include <iostream>
using namespace std;

class building {
friend class goodgay;   //声明友元类
public:
	building();
	string keting;
private:
	string cesuo;
protected:
	string woshi;
};
building::building() {
	keting = "客厅";
	cesuo = "厕所";
	woshi = "卧室";
}

class goodgay {
public:
	goodgay();
	void show();
private:
	building* p;
};
void goodgay::show() {
	cout << this->p->keting << ' ' << this->p->cesuo << ' ' << this->p->woshi << endl;
}
goodgay::goodgay() {
	p = new building;
}
void f() {
	goodgay a;
	a.show();
}
int main() {
	f();
	return 0;
}

 类做友元,类中的所有成员函数都能访问友元类中所有成员。

 6.3成员函数做友元

 代码:

#include <iostream>
using namespace std;
class building;
class goodgay {
public:
	goodgay();
	void show1(building& p);
private:
	building* p;
};

class building {
friend void goodgay::show1(building& p);   //声明友元类
public:
	building();
	string keting;
private:
	string cesuo;
protected:
	string woshi;
};
building::building() {
	keting = "客厅";
	cesuo = "厕所";
	woshi = "卧室";
}


void goodgay::show1(building& p1) {
	cout <<p1.keting << ' ' << p1.cesuo << ' ' << p1.woshi << endl;
}
//void goodgay::show2() {
//	cout << this->p->ketipng << ' ' << this->p->cesuo << ' ' << this->p->woshi << endl;
//}
//无权限
goodgay::goodgay() {
	p = new building;
}
void f() {
	goodgay a;
	building b;
	a.show1(b);
}
int main() {
	f();
	return 0;
}

注意类要先声明一下,防止报错,与全局函数做友元不同的是,要加上作用域。

更多推荐

9、DVWA——XSS(Stored)

文章目录一、存储型XSS概述二、low2.1源码分析2.2通关分析三、medium3.1源码分析3.2通关思路四、high4.1源码分析4.2通关思路一、存储型XSS概述XSS,全称CrossSiteScripting,即跨站脚本攻击,某种意义上也是一种注入攻击,是指攻击者在页面中注入恶意的脚本代码,当受害者访问该页面

分布式系统中的选举,日志副本,安全等设计思想

链接:https://pan.baidu.com/s/1G9295khav7_k3dD9G0f_Kw?pwd=q216提取码:q216领导选举领导选举(Leaderelection)是在分布式系统中选择一个节点作为领导者或协调者的过程。分布式系统通常由多个节点组成,每个节点都可以执行特定的任务。然而,为了使系统有序运行

HCIE-容器docker

1、安装配置操作系统,使用CentOSstream8镜像之前:RHEL8.4发布了,CentOS紧随其后,发布CentOS8.4之后:CentOS走在前面,成为RHEL上游,再去发布RHEL制作模板,模板配置要求,cpu至少2个,内存建议4G,硬盘100G,网卡使用NAT模式。1.编辑网卡[root@tempnetwo

Java|List.subList 踩坑小记

很久以前在使用Java的List.subList方法时踩过一个坑,当时记了一条待办,要写一写这事,今天完成它。我们先来看一段代码://初始化list为{1,2,3,4,5}List<Integer>list=newArrayList<>();for(inti=1;i<=5;i++){list.add(i);}//取前3

传感器浮点数数据在串口通信中封包技术解析

一、项目实现要求根据项目要求,我们需要在多台机器人间进行数据通信,系统搭建如下:在机器人A上搭载大气压模块传感器和zigbee通信模块,在机器人B上搭载手势传感器和zigbee通信模块,在机器人C上搭载zigbee通信模块,要求A和B的传感器数据能够通过zigbee模块传输到机器人C并用以做进一步的控制处理。二、由于分

word的分隔符和分页符

目录1.word中的分隔符和分页有何不同2.word中我想把表格所在的页设置为横向,上下页均为纵向3.表格页末尾的光标回车生成新的页面后,其仍然为横向,而我希望它为纵向1.word中的分隔符和分页有何不同分隔符和分页符在Word中都是用于文本分段的工具,但它们的用途和操作方式有所不同。分隔符是一个广义的概念,包括分页符

MYSQL的锁

概述锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更

LVS 负载均衡集群的DR模式配置

集群集群的概述集群技术是一种用于提高系统性能、可用性、容错性和可扩展性的关键方法。它涉及将多个计算资源或节点组合在一起,以协同工作以处理任务、服务请求或数据处理。集群类型无论是哪种集群,都至少包括两台节点服务器,而对外表现成一个整体,只提供一项服务,相当于一台大型计算机。根据群集所针对的目标差异,可分为三种类型的集群负

分布式ETL工具Sqoop实践

Mysql数据准备1、在node02节点登录Mysql。mysql-uroot-proot2、新建数据库testdb。createdatabasetestdb;3、新建数据表ts。usetestdb;createtablets(idint,namevarchar(10),ageint,sexchar(1));4、向表中

hive中的索引

使用索引前的配置在使用Hive索引之前,需要进行一些配置,以确保索引能够正常工作。以下是一些常见的配置步骤:Hive配置在Hive中启用索引功能,需要在Hive配置文件(hive-site.xml)中设置以下属性:<property><name>hive.index.compact.file.uris</name><v

【日记】文章更新计划

有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top文章最后有详细的更新计划{%timeline2023,pink%}第一版发布【完结~开发规范系列】Linux系列重新定位,不再只是简单的说常用命令周二rocketmq更换为nginx系列微服务内容变

热文推荐