NO.38结构体和类|初始化|操作|访问|嵌套|运算符重载|结构体排序|类|访问权限|结构体和类区别(C++)

结构体

结构体是⼀种⾃定义的类型,使⽤这种⾃定义类型可以描述⼀些复杂对象。
前⾯我们学习的都是单⼀的数据类型,⽐如: char 、 short 、 int 、 double 类型,但是我们现实⽣活中总是有写复杂对象,⽐如:⼈、书等,这些复杂对象,仅仅使⽤单⼀的数据类型是不能描述的。⽐如:描述⼀本书,书有作者、出版社、定价等信息;描述⼀个⼈,⼈有名字、性别、年龄、⾝⾼、体重等信息。那怎么描述这些复杂对象呢?
C++中引⼊了结构体和类来解决这些问题。在C++中结构体和类是相似的,这⾥⾸先介绍结构体

结构体类型声明和变量定义

结构体类型声明的关键字是 struct ,结构体类型声明的基本语法如下

struct tag  
{  
	成员变量列表; //成员变量可以有1个,也可以有多个  
	成员函数列表; //成员函数可以有,也可以没有  
} 结构体变量列表; 
//在声明结构体类型的同时,创建结构体变量,可以有多个,中间使⽤逗号隔开
struct Stu  
{  
	string name;  
	int chinese;  
	int math;  
	int total;  
} s1, s[50];
struct Stu  
{  
	string name;  
	int chinese;  
	int math;  
	int total;  
}; //结构体类型  

struct Stu s1;  
Stu s1; //可以省略struct  
Stu s[50];
  1. 在创建变量的时候,结构体类型中的 struct 就可以省略了。
  2. 在创建结构体变量的时候,结构体变量的名字不能和结构体类型的名字相同。
  3. 声明的结构体类型是不占⽤内存空间,当使⽤结构体类型创建了变量后,才向内存申请了空间的。
  4. 结构体变量可以是全局变量,也可以是局部变量。

结构体变量的特点

结构体的初始化

结构体的初始化和数组类似,使⽤ {} ,将初始化的内容按照顺序放在 {} 中就可以。

struct Stu  
{  
	string name;  
	int chinese;  
	int math;  
	int total;
};  
struct Stu s1 = {"zhangsan", 85, 95, 180};
结构体整体操作

结构体变量中虽然包含多个成员,⽽且成员可能是不同类型的。
但是⼀个结构体变量可以看做⼀个整体,是可以直接进⾏赋值操作的。

struct Stu s1 = {"zhangsan", 85, 95, 180};  
struct Stu s2;  
s2 = s1;//整体赋值,这样s2的内容就会和s1的⼀样
结构体成员的访问

结构体成员访问的基本形式是

结构体变量.成员名

因为每个结构体变量中都有属于⾃⼰的成员,所有必须使⽤ . 这种结构体成员访问操作符。
通过这种⽅式找到成员后,可以直接给结构体变量的成员中输⼊值,或者直接存储和使⽤

#include <iostream>  
using namespace std;  
struct Stu  
{  
	string name;  
	int chinese;  
	int math;  
	int total;  
};  
int main()  
{  
	struct Stu s1;  
	s1.name = "lisi"; //直接赋值  
	s1.chinese = 95;  
	cin >> s1.math; //输⼊  
	s1.total = s1.chinese + s1.math; //结构体成员直接参与运算  
	cout << s1.total << endl; //输出操作  
	return 0;  
}
结构体嵌套

当然如果结构体中嵌套了其他结构体成员,这⾥初始化的时候,也可以 {} 中嵌套 {} ,访问嵌套成员中的成员可以连续使⽤ . 操作符

struct Score  
{  
	int chinese;  
	int math;  
	int engish;  
};  
struct Stu  
{  
	string name;  
	struct Score score;  
	int total;
	int avg;  
};  
int main()  
{  
	struct Stu s = {"wangwu", {80, 90, 100}, 0, 0}; //初始化  
	s.total = s.score.chinese + s.score.engish + s.score.math; 
	//嵌套成员的访问  
	s.avg = s.total / 3;  
	cout << s.total << endl;  
	cout << s.avg << endl;  
	return 0;  
}

结构体的成员函数

以上我们讲的是结构体的基本知识,C语⾔中的结构体就是这样的,但是C++中的结构体和C语⾔结构体的有⼀个⽐较⼤的差异就是:C++中的结构体中除了有成员变量之外,还可以包含成员函数。

  1. C++的结构体会有⼀些默认的成员函数,⽐如:构造函数、析构函数等,是编译器默认⽣成的,如果觉得不合适,也是可以⾃⼰显⽰的定义这些函数,这些函数都是⾃动被调⽤,不需要⼿动调⽤。
  2. 除了默认的成员函数之外,我们可以⾃⼰定义⼀些成员函数,这些成员函数可以有,也可以没有,完全根据的实际的需要来添加就可以。
  3. 这些成员函数可以直接访问成员变量
  4. 成员函数的调⽤也使⽤ . 操作符
//代码1-演⽰⾃定义成员函数  
#include <iostream>  
using namespace std;  
struct Stu  
{  
	//成员变量  
	string name;  
	int chinese;  
	int math;  
	int total;  
	
	void init_stu() //初始化  
	{  
		name = "⼩明";
		chinese = 99;  
		math = 95;  
		total = math + chinese;  
	}  
	
	void print_stu() //打印  
	{  
		cout << "名字:" << name << endl;  
		cout << "语⽂:" << chinese << endl;  
		cout << "数学:" << math << endl;  
		cout << "总分:" << total << endl;  
	}  
};  

int main()  
{  
	struct Stu s;  
	s.init_stu();  
	s.print_stu();  
	return 0;  
}
构造函数和析构函数
构造函数:

构造函数是结构中默认的成员函数之⼀,构造函数的主要的任务是初始化结构体变量。写了构造函数,就不需要再写其他成员函数来初始化结构体(类)的成员,⽽且构造函数是在结构变量创建的时候,编译器⾃动被调⽤的。
构造函数的特征如下:

  • 函数名与结构体(类)名相同。
  • ⽆返回值。
  • 构造函数可以重载。
  • 若未显式定义构造函数,系统会⾃动⽣成默认的构造函数。
析构函数:

析构函数是⽤来完成结构体变量中资源的清理⼯作,也是结构体中默认的成员函数之⼀。析构函数在结构体变量销毁的时候,被⾃动调⽤的。
析构函数的特征如下:

  • 析构函数名是在结构体(类)名前加上字符 ~ 。
  • ⽆参数⽆返回值类型。
  • ⼀个类只能有⼀个析构函数。若未显式定义析构函数,系统会⾃动⽣成默认的析构函数。注意:析构函数不能重载
//代码2-演⽰构造和析构函数  
#include <iostream>  
using namespace std;  
struct Stu  
{  
	//成员变量  
	string name;  
	int chinese;  
	int math;  
	int total;  
	
	//构造函数  
	Stu()  
	{  
		cout << "调⽤构造函数" << endl;  
		name = "⼩明";  
		chinese = 99;  
		math = 95;  
		total = math + chinese;  
	}  
	
	//析构函数  
	~Stu()  
	{  
		cout << "调⽤析构函数" << endl;  
		//对于当前这个类的对象没有啥资源清理  
	}  
	
	void print_stu() //打印  
	{  
		cout << "名字:" << name << endl;  
		cout << "语⽂:" << chinese << endl;  
		cout << "数学:" << math << endl;  
		cout << "总分:" << total << endl;  
	}  
};  

int main()  
{
	struct Stu s;  
	s.print_stu();  
	return 0;  
}

运算符重载

在上⼀个代码的例⼦中,在打印结构体成员信息的时候,我们是通过 s.print_stu() 的⽅式完成的
但是我们在C++中打印数据的时候,习惯了直接使⽤ cout 来直接打印数据的。⽐如

int n = 100;  
float f = 3.14f;  
cout << n << endl;  
cout << f << endl;

针对 struct Stu 类型的变量能不能直接使⽤ cout 来打印

#include <iostream>  
using namespace std;  
struct Stu  
{  
	//成员变量  
	string name;  
	int chinese;  
	int math;  
	int total;  
};  

int main()  
{  
	struct Stu s = {"张三", 90, 80, 170};  
	cout << s << endl;
	return 0;  
}

![[Pasted image 20250314100017.png]]

在C++中要针对⾃定义类型的变量,想使⽤ cout 和 << 来输出变量的内容,就得对 << 这个输出运算符进⾏重载

#include <iostream>  
using namespace std;  
struct Stu  
{  
	//成员变量  
	string name;  
	int chinese;  
	int math;  
	int total;  
};  

//重载输出运算符  
ostream& operator<< (ostream& os, const Stu & s)  
{  
	os << "名字: " << s.name << endl;  
	os << "语⽂: " << s.chinese << endl;  
	os << "数学: " << s.math << endl;  
	os << "总分: " << s.total << endl;  
	return os;  
}  

int main()  
{  
	struct Stu s = {"张三", 90, 80, 170};  
	cout << s << endl;  
	return 0;  
}

结构体排序-sort

说到排序,我们之前讲过冒泡排序,我们也可以写⼀个冒泡排序函数来排序⼀组结构体数据,这⾥介绍⼀个C++的STL中的库函数 sort ,可以直接⽤来排序数据,在算法竞赛和⽇常开发中使⽤⾮常频繁。
只要涉及到数据的排序,⼜没有明确要求⾃⼰实现排序算法的时候,就可以直接使⽤sort函数

sort函数介绍
//版本1  
template <class RandomAccessIterator>  
void sort (RandomAccessIterator first, RandomAccessIterator last);  
//void sort(开始位置,结束位置);  
//first:指向要排序范围的第⼀个元素的迭代器或者指针。  
//last:指向要排序范围的最后⼀个元素之后位置的迭代器或者指针。  
//版本2  
template <class RandomAccessIterator, class Compare>  
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare  
comp);  
//void sort(开始位置,结束位置,⾃定义排序函数);  
//first:指向要排序范围的第⼀个元素的迭代器或者指针。  
//last:指向要排序范围的最后⼀个元素之后位置的迭代器或者指针。  
//comp:是⼀个⽐较函数或者函数对象  
//这⾥开始位置和结束位置,可以是指针,也可以是迭代器  
//⾃定义排序函数 可以是函数,也可以是仿函数

在默认情况下 sort 函数,按升序对给定范围[first,last)中的元素进⾏排序
![[Pasted image 20250314100240.png]]

sort 函数需要包含的头⽂件 <algorithm>

排序内置类型数据
  • 对数组进⾏排序
#include <iostream>  
#include <algorithm>  
using namespace std;  
int main()  
{  
	int arr[] = { 4,5,6,9,7,1,2,8,5,4,2 };  
	int size = sizeof(arr) / sizeof(arr[0]);  
	//起始位置和结束位置传的是地址  
	sort(arr, arr + size);  
	for (int i = 0; i < size; i++)  
	{  
		cout << arr[i] << " ";  
	}  
	cout << endl;  
	return 0;  
}

![[Pasted image 20250314100330.png]]

默认排序结果是升序的

  • 对字符串中的字符进⾏排序
    这⾥是对字符串中字符的顺序进⾏排序,是按照字符的ASCII值进⾏排序的
#include <iostream>  
#include <algorithm>  
using namespace std;  
int main()  
{
	string s("defxxxabccba");  
	sort(s.begin(), s.end());  
	cout << s << endl;  
	return 0;  
}

![[Pasted image 20250314100413.png]]

默认排序的结果依然是升序

⾃定义排序

sort 在默认的情况下是按照升序排序,如何按照降序排序呢?结构体类型数据进⾏排序 使⽤⾃定义排序⽅式

void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

sort 的第三个参数是⼀个可选的⾃定义⽐较函数(或函数对象),⽤于指定排序的规则。如果不提供这个参数, std::sort 默认会使⽤⼩于运算符( < )来⽐较元素,并按照升序排序
这个⽐较函数,接受两个参数,并返回⼀个布尔值。如果第⼀个参数应该排在第⼆个参数之前,则返回true;否则返回false。
comp 表⽰可以⾃定义⼀个排序⽅法

创建⽐较函数
#include <iostream>  
#include <algorithm>  
using namespace std;  
//
//⾃定义⼀个⽐较函数,这个⽐较函数能够⽐较被排序数据的2个元素⼤⼩  
//函数返回bool类型的值  
//  
bool compare(int x, int y)  
{  
	return x > y;//排降序  
}  

int main()  
{  
	int arr[] = { 4,5,6,9,7,1,2,8,5,4,2 };  
	int size = sizeof(arr) / sizeof(arr[0]);  
	//将函数名作为第三个参数传⼊sort函数中  
	sort(arr, arr + size, compare);  
	for (int i = 0; i < size; i++)  
	{  
		cout << arr[i] << " ";  
	}  
	cout << endl;  
	return 0;  
}
结构体中重载()运算符-仿函数
#include <iostream>  
#include<algorithm>  
using namespace std;  
//仿函数⽅式 - 仿函数也叫函数对象  
  
struct Cmp  
{  
	bool operator()(int x, int y)  
	{  
		return x > y;//排降序  
	}  
}cmp;  

int main()  
{  
	int arr[] = { 4,5,6,9,7,1,2,8,5,4,2 };  
	int size = sizeof(arr) / sizeof(arr[0]);  
	//将结构体对象作为第三个参数传⼊sort函数中  
	sort(arr, arr + size, cmp);
	for (int i = 0; i < size; i++)  
	{  
		cout << arr[i] << " ";  
	}  
	cout << endl;  
	return 0;  
}

![[Pasted image 20250314100743.png]]

排序结构体数据

两个结构体数据也是不能直接⽐较⼤⼩的,在使⽤ sort 函数排序的时候,也是需要提供⾃定义的⽐较⽅法

#include <iostream>  
#include <algorithm>  
using namespace std;  
struct S  
{  
	string name;  
	int age;  
};  

bool cmp_s_by_age(const struct S& s1, const struct S& s2)  
{  
	return s1.age > s2.age; //按年龄降序  
	}  
		bool cmp_s_by_name(const struct S& s1, const struct S& s2)  
	{  
	return s1.name > s2.name;//按名字降序  
}  

//测试⾃定义⽐较函数  
void test1()  
{  
	struct S s[3] = { {"zhangsan", 20}, {"lisi", 25}, {"wangwu", 18} };
	sort(s, s + 3, cmp_s_by_age);  
	int i = 0;  
	for (i = 0; i < 3; i++)  
	{  
		cout << s[i].name << " " << s[i].age << endl;  
	}  
}  

struct CmpByNameLess  
{  
	bool operator()(const struct S& s1, const struct S& s2)  
	{  
		return s1.name < s2.name; //按照名字升序  
	}  
};  

struct CmpByAgeGreater  
{  
	bool operator()(const struct S& s1, const struct S& s2)  
	{  
		return s1.age > s2.age; //按照年龄降序  
	}  
};  

//测试结构中重载()运算符实现⽐较  
void test2()  
{  
	struct S s[3] = { {"zhangsan", 20}, {"lisi", 25}, {"wangwu", 18} };  
	sort(s, s + 3, CmpByNameLess);  
	int i = 0;  
	for (i = 0; i < 3; i++)  
	{  
		cout << s[i].name << " " << s[i].age << endl;  
	}  
}  

int main()  
{  
	test1();  
	test2();  
	
	return 0;  
}

C++中为了更好的实现⾯向对象,更喜欢使⽤ class (类)来替换 struct (结构体)。你可以简单粗暴的理解为 class 和 struct 是⼀回事,但是其实本上还是有区别的

类定义

类的关键字是 class ,类中主要也是由两部分组成,分别为成员变量和成员函数

class tag  
{  
	public:  
	成员变量列表;  
	成员函数列表;  
}; // ⼀定要注意后⾯的分号

class 是⽤来定义类类型的关键字,在类中可以定义成员函数和成员变量。
public 是类成员权限访问限定符,标志类中的成员可以公开访问及调⽤

  • 包含成员变量的类,例如描述⼀个学⽣
class Stu  
{  
	public:  
	string name; //名字  
	int chinese; //语⽂成绩  
	
	int math;  //数学成绩 
	int total; //总成绩

};
  • 包含成员变量和成员函数的类
class Stu  
{  
	public:  
	void init_stu()  
	{  
		name= "⼩明";  
		chinese = 0;  
		math = 0;  
		total = 0;  
	}  
	string name; //名字  
	int chinese; //语⽂成绩  
	
	int math;   //数学成绩
	int total;  //总成绩

};

在类中,成员变量和成员函数都是没有数量限制的,即可以有多个成员变量或成员函数

类的使⽤

创建类对象
int main()  
{  
	Stu s1;   //创建类对象s1
	Stu s2;   //创建类对象s2
	
	return 0;
}
调⽤类对象成员

像结构体⼀样,通过操作符( . )即可对类对象的成员进⾏访问

#include <iostream>  
using namespace std;  
int main()  
{  
	//创建类对象  
	Stu s1;  
	//调⽤成员变量
	s1.name = "张三";  
	s1.chinese = 90;  
	s1.math = 98;  
	s1.total = s1.chinese + s1.math;  
	Stu s2;  
	//调⽤成员函数  
	s2.init_stu();  
	
	return 0;  
}

访问权限控制

访问限定符是C++语⾔中的关键字,⽤于指定类成员的访问权限。
访问限定符主要有三个:

  • public :成员被声明为 public 后,可以被该类的任何⽅法访问,包括在类的外部。
  • protected :成员被声明为 protected 后,可以被该类访问。
  • private :成员被声明为 private 后,只能被该类的成员函数访问
#include <iostream>  
using namespace std;  
class Stu  
{  
public: //将成员函数设置为公有属性  
	void init_stu()  
	{  
	name= "⼩明";  
	chinese = 0;  
	math = 0;  
	total = 0;
	}  


private://将成员变量设置为私有属性
	string name; //名字  
	int chinese; //语⽂成绩
	int math;   //数学成绩
	int total;  //总成绩
};

int main()  
{  
	Stu stu;  
	
	stu.init_stu();   //访问公有成员函数
	cout << stu.name << endl;  //访问私有成员变量,编译器报错
	return 0;
}

通过运⾏结果可⻅,类外可直接访问设置为公有的成员,⽽不可以直接访问私有的成员

习惯上,外部可访问的成员函数通常设置为公有属性( public ),⽽为了提⾼成员变量的访问安全性,通常将成员变量设置为私有属性( private ),即只有类内部可以访问

结构体和类的区别

C++中 struct 和 class 的区别是什么?
C++兼容了C语⾔,所以C++中 struct 既可以当成结构体使⽤,还可以⽤来定义类,和 class 定义类是⼀样的。区别是 struct 定义的类默认访问权限是 public , class 定义的类默认访问权限是 private 。

类的定义既可以使⽤ struct ,也可以使⽤ class
C++更常⽤ class 关键词来定义类,因此在选⽤ class 的时候需要加上访问限定符 public 才可以在类外调⽤类的成员函数和成员变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值