目录
1.结构体类型的声明、创建与使用(结构体嵌套+成员变量)
cpp
#include<iostream>
#include<string>
using namespace std;
struct Stu{
string name;
int age;
int total;
}s1,s2[10];
int main()
{
struct Stu s3;
Stu s4;
Stu s5[10];
return 0;
}
代码重点解释:
- s3与s1的创建是同样效果的,只是一个是直接在结构体声明后直接创建,一个是初始化创建
- s2[10]表示说创建了一个Stu结构体数组,可以看作是由10个Stu类型的变量所组成的数组;同时,也可以通过初始化创建结构体数组s5
- 在C++中,初始化创建结构体变量时struct可以被省略,这与C语言是截然不同的
- 声明后可以同时创建零个或多个变量(数组类型、指针类型都可),多个变量之间用逗号隔开,并且声明后创建的变量都为全局变量(在main函数外创建的)
- 注意事项:结构体变量的名字和结构体类型的名字不能相同,声明的结构体类型不占用内存,创建完结构体变量后才会申请内存
cpp
#include<iostream>
#include<string>
using namespace std;
struct Stu{
string name;
int age;
int total;
}s1;
int main()
{
s1 = {"zhangsan",20,100};
Stu s2 = s1;
cout<<s1.name<<" "<<s2.name<<endl;
Stu s3;
cin>>s3.name>>s3.age>>s3.total;
cout<<s3.name<<s3.age;
return 0;
}
代码重点解释:
cpp
#include<iostream>
#include<string>
using namespace std;
struct score{
int chinese;
int math;
int english;
};
struct stu{
string name;
score sc;
int total;
};
int main()
{
stu s1 = {"zhangsan",{100,80,90},0};
cout<<s1.sc.chinese;
return 0;
}
结构体的嵌套使用就是结构体某个成员变量为结构体,所以就是在使用结构体的结构体成员的成员变量
2.结构体类型的成员函数(重点)
成员函数是c++区别于c语言的一种特殊写法,c++结构体会有一些默认的成员函数,如构造函数、析构函数(可以看作初始化函数与自动销毁函数)等,这些函数都会被自动调用,不需要手动调用;当然,这些默认的构造函数与析构函数也可以自定义声明,但自动调用的性质不会改变
除了默认的成员函数,还可以自定义一些成员函数,这些成员函数可以有也可以没有;它们可以直接访问成员变量,调用时也是用 . 操作符
cpp
#include<iostream>
#include<string>
using namespace std;
struct score{
int chinese;
int math;
int english;
//构造函数
score(int c,int m,int e)
{
chinese = c;
math = m;
english = e;
}
score()
{
cout<<"函数重载进行中"<<endl;
}
//析构函数
~score()
{
cout<<"程序结束"<<endl;
}
//score(int c,int m,int e);
//score(int c,int m,int e):chinese(c),math(m),english(e){}
};
//score::score(int c,int m,int e)
//{
// chinese = c;
// math = m;
// english = e;
//}
int main()
{
{
score s1(100,30,40);
cout<<s1.chinese<<endl;
}
score s2;
return 0;
}
代码重点解释:
- 构造函数可以看作是创建出一个结构体对象后,直接给到结构体对象3个值,这3个值赋值给了3个成员对象;如果没有这样的一个构造函数,那就相当于跳过了构造函数进行成员对象的赋值
- 析构函数指的是在一个结构体对象的生命周期结束时,自动销毁或手动销毁以前进行一系列的操作,这些操作就写在了析构函数中
- 构造函数的名字为该函数所在结构体的结构体名称,不需要声明返回类型;析构函数的名称同构造函数,需要在函数名前加上一个 ~
- 可以选择先在结构体中声明构造函数、析构函数或自定义函数,然后在结构体的外部进行定义(注释代码)
- score(int c,int m,int e):chinese(c),math(m),english(e){} 构造函数的第二种写法,函数名+参数声明+成员变量的直接赋值+构造函数内部操作,一个也不能省略(全都要有!!!)
- 注意:构造函数可以重载,析构函数不可以重载!!!
cpp
#include<iostream>
#include<string>
using namespace std;
struct score{
int chinese;
int math;
int total;
void init_sc()
{
chinese = 100;
math = 90;
total = chinese + math;
}
void print()
{
cout<<total;
}
}s1;
int main()
{
s1.init_sc();
s1.print();
return 0;
}
自定义了一个成员函数,成员函数中直接调用了成员变量进行赋值,创建完结构体变量s1后,调用完该成员函数后,再调用print成员函数(打印total成员变量的函数),打印出来为190
3.操作符重载
cpp
#include<iostream>
#include<string>
using namespace std;
struct score{
int chinese;
int math;
int english;
};
ostream& operator<<(ostream& os,struct score& s)
{
os<<s.chinese<<" "<<s.english<<" "<<s.math;
return os;
}
int main()
{
score s1={100,90,80};
cout<<s1<<endl;
return 0;
}
对输出流运算符进行了操作符重载,c++中每个操作符的底层是一个函数,例如<<操作符的函数返回类型为ostream&,参数为输出流以及输出对象;操作符重载相当于给予<<一个新的函数定义,让他具备新的功能,这样输出流操作符就能一次性把结构体对象的所有内容都打印了
cpp
#include <iostream>
using namespace std;
class Time {
public:
int hours; // 小时
int minutes; // 分钟
Time() {
hours = 0;
minutes = 0;
}
Time(int h, int m) {
this->hours = h;
this->minutes = m;
}
void show() {
cout << hours << " " << minutes << endl;
}
// write your code here......
Time operator+(Time &t)
{ Time sb;
sb.hours=this->hours+t.hours;
sb.minutes=this->minutes+t.minutes;
if(sb.minutes>=60)
{ int i=0;
sb.hours+=sb.minutes/60;
++i;
sb.minutes=sb.minutes-60*i;
}
return sb;
}
};
int main() {
int h, m;
cin >> h;
cin >> m;
Time t1(h, m);
Time t2(2, 20);
Time t3 = t1 + t2;
t3.show();
return 0;
}
当我们需要对某个类创建出来的对象,或者某个结构体创建出来的变量,+-×÷进行运算符重载时,需要在类、结构体的定义里进行
先定义了一个变量sb,先调用了对象自身(this指针),然后调用了另外一个对象;让自己的时间、分钟进行一些操作以后给到变量sb,然后返回以后即完成操作符重载
cpp
#include <iostream>
class Complex {
private:
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
void display() const {
std::cout << real << " + " << imag << "i" << std::endl;
}
// 声明为友元,让全局函数能访问私有成员
friend Complex operator-(const Complex& c);
friend Complex& operator++(Complex& c); // 前置++
friend Complex operator++(Complex& c, int); // 后置++
friend bool operator!(const Complex& c);
};
// 全局重载负号运算符
Complex operator-(const Complex& c) {
return Complex(-c.real, -c.imag);
}
// 全局重载前置自增运算符
Complex& operator++(Complex& c) {
++c.real;
++c.imag;
return c;
}
// 全局重载后置自增运算符
Complex operator++(Complex& c, int) {
Complex temp = c;
c.real++;
c.imag++;
return temp;
}
// 全局重载逻辑非运算符
bool operator!(const Complex& c) {
return (c.real == 0 && c.imag == 0);
}
int main() {
Complex c1(3, 4);
Complex c2 = -c1; // 使用全局重载的负号运算符
c2.display(); // 输出: -3 + -4i
++c1; // 使用全局重载的前置++
c1.display(); // 输出: 4 + 5i
Complex c3 = c1++; // 使用全局重载的后置++
c3.display(); // 输出: 4 + 5i
c1.display(); // 输出: 5 + 6i
Complex c4(0, 0);
if (!c4) { // 使用全局重载的逻辑非
std::cout << "c4 is zero" << std::endl;
}
return 0;
}
在全局进行运算符重载也是可行的,声明完要重载的操作符以后,声明为友元,让全局函数能够访问私有成员

4.sort函数和结构体的排序(重点)
1)数组排序

- 如上图所示,sort函数是对[first,last)区间进行排序,last、first都是指数组指针
- sort函数在algorithm头文件中
- 数组名就是首元素地址,即为first;因为左闭右开,所以last需要是数组最后一个元素的后一个地址;从first到last之间的元素个数应该是 sizeof(arr)/sizeof(a[0])
cpp
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int arr[10]={3,4,1,5,9,10,3,8,19,-1};
int sz = sizeof(arr)/sizeof(arr[0]);
sort(arr,arr+sz);
for(int i=0;i<sz;i++) cout<<arr[i]<<" ";
return 0;
}
2)字符串排序
字符串排序可以用到begin、end函数
cpp
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int main()
{
string st = "ahasdnjdbadsb";
sort(st.begin(),st.end());
cout<<st;
return 0;
}
3.1)自定义排序(排序函数)
- sort函数有3个参数,起始位置、终止位置和bool类型的排序函数
- 排序函数默认为less函数(升序排序),可以切换成greater函数,sort的less、greater函数()不能省,priority_queue的less、greater函数()必须省
- 排序函数接收两个参数(每次用来比较的2个参数),并返回一个布尔值。
- 排序函数的2个参数一开始的位置为第一个在前,第二个在后。排序函数为true时,参数位置不变;为false时,参数进行位置交换
cpp
#include<iostream>
#include<algorithm>
using namespace std;
bool cmp(int x,int y)
{
return x>y;
}
int main()
{
int arr[10]={3,4,1,5,9,10,3,8,19,-1};
int sz = sizeof(arr)/sizeof(arr[0]);
sort(arr,arr+sz,cmp);
for(int i=0;i<sz;i++) cout<<arr[i]<<" ";
cout<<endl;
sort(arr,arr+sz,less<int>());
for(int i=0;i<sz;i++) cout<<arr[i]<<" ";
return 0;
}
3.2)自定义排序(仿函数)
不同于priority_queue是对 < 进行操作符重载,来实现排序方式的改变;sort函数是可以通过一个结构体对象,这个对象包含了对()操作符的重载,来实现排序方式的改变
cpp
#include<iostream>
#include<algorithm>
using namespace std;
struct Cmp{
bool operator()(int x,int y)
{
return x>y;
}
}cmp;
int main()
{
int arr[10]={3,4,1,5,9,10,3,8,19,-1};
int sz = sizeof(arr)/sizeof(arr[0]);
sort(arr,arr+sz,cmp);
for(int i=0;i<sz;i++) cout<<arr[i]<<" ";
return 0;
}
3.3)自定义函数(匿名函数)
c++11标准下,创新了一个名为lambda表达式的东西,可以理解成简化表达的一个函数,这样的函数不需要规定函数返回类型,以下是匿名函数的一些表达式讲解
\] // 不捕获任何外部变量
=\] // 隐式按值捕获所有外部变量
=, \&x\] // 按引用捕获x,其余按值捕获
() //获取函数参数
\] 主要用来捕捉局部变量,全局变量与静态局部变量不需要捕捉可以直接访问
lambda表达式在C++99标准下不可用!!!
cpp
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int arr[10]={3,4,1,5,9,10,3,8,19,-1};
int sz = sizeof(arr)/sizeof(arr[0]);
sort(arr,arr+sz,[](int x,int y)
{
return x>y;
});
for(int i=0;i<sz;i++) cout<<arr[i]<<" ";
return 0;
}
4)结构体排序
cpp
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
struct Stu
{
string name;
int age;
}arr[3]={{"zhangsan",20},{"lisi",35},{"wangwu",19}};
ostream& operator<<(ostream& os,Stu& s)
{
os<<s.name<<" "<<s.age;
return os;
}
bool cmp_s_byage(Stu s1,Stu s2)
{
return s1.age<s2.age;
}
int main()
{
int sz = sizeof(arr)/sizeof(arr[0]);
sort(arr,arr+sz,cmp_s_byage);
for(auto& st:arr) cout<<st<<endl;
return 0;
}
根据年龄大小进行排序,依旧使用排序函数,只是需要把排序函数中的参数类型给更换以下即可
cpp
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
struct Stu
{
string name;
int age;
}arr[3]={{"zhangsan",20},{"lisi",35},{"wangwu",19}};
ostream& operator<<(ostream& os,Stu& s)
{
os<<s.name<<" "<<s.age;
return os;
}
int main()
{
int sz = sizeof(arr)/sizeof(arr[0]);
sort(arr,arr+sz,[](Stu s1,Stu s2)
{
return s1.age>s2.age;
});
for(auto& st:arr) cout<<st<<endl;
return 0;
}
也可以将排序函数给简化成一个匿名函数,这样代码能够更加简洁,仿函数也只是将参数类型切换即可,此处省略
5.类的声明、创建与使用
cpp
class tag{
public:
//成员变量列表
//成员函数列表
};
类的声明与定义与struct类型一样,都可以包含成员变量、成员函数(类也有构造函数与虚构函数)
需要注意的是:结构体类型下,默认访问形式是public的;类下默认访问形式是private的
cpp
#include<iostream>
using namespace std;
class tag{
public:
string name;
int age;
};
int main()
{
tag s1;//创建类tag的对象s1
s1.age = 20;
s1.name = "zhangsan";
return 0;
}
类创建出来的变量,我们也可以称其为一个对象
类的创建、使用与结构体类型也一样,只是在调用成员时的访问限制不同
访问限制修饰符的限制层级:
