4128人加入学习
(13人评价)
C++编程系列 第二季函数和类

制作于2018.4.2

价格 免费

用户通常需要创建同一个类的多个对象,这种情况下,可以创建独立对象变量,也可以创建对象数组

声明对象数组的方法与声明标准类型数组相同。

Student stus[5]; //声明了一个有5个Student对象的数组

注意:要创建类对象数组,则这个类必须有默认构造函数。因为初始化对象数组时,会首先用默认构造函数创建数组元素。

#include "pch.h"
#include "Cuboid.h"
#include <iostream>

using namespace std;

int main()
{
	Cuboid c1(20, 10.5, 11.5);
	Cuboid c2(11.5, 22, 9.5);

	Cuboid cs[2] = {};
	cs[0] = Cuboid(20, 10, 11);
	cs[1] = Cuboid(1, 4.5, 9);//cs[1](11,26,9);//隐式的无法实现,报错

	int res = c1.compare(c2);
	res = cs[0].compare(cs[1]);
	if (res == 0)
	{
		cout << "第一个长方体的体积大于第二个长方体的体积" << endl;
	}
	else if (res == 1)
	{
		cout << "两个长方体的体积相等" << endl;
	}
	else
	{
		cout << "第一个长方体的体积小于第二个长方体的体积" << endl;
	}
	return 0;
}

[展开全文]

this指针:每一个对象都能通过this指针来访问自己的地址。在成员函数内部,它可以用来指向调用对象。

有时候方法可能涉及到两个对象,在这种情况下就需要使用this指针。

 

//Cuboid.h

#pragma once

#ifndef CUBOID_H_
#define CUBOID_H_
class Cuboid
{
private:
	double length_;
	double width_;
	double height_;

public:
	Cuboid(double length, double width, double height);
	Cuboid();
	~Cuboid();
	double volume() { return length_ * width_*height_; };
	int compare(Cuboid & c);
};
#endif // !CUBOID_H_

//Cuboid.cpp

#include "pch.h"
#include "Cuboid.h"


Cuboid::Cuboid(double length, double width, double height)
{
	length_ = length;
	width_ = width;
	height_ = height;
}

Cuboid::Cuboid()
{
}


Cuboid::~Cuboid()
{
}

int Cuboid::compare(Cuboid & c)
{
	if (this->volume() > c.volume())
	{
		return 0;
	}
	else if (this->volume() == c.volume())
	{
		return 1;
	}
	else
	{
		return 2;
	}
}

//19-this指针.cpp

#include "pch.h"
#include "Cuboid.h"
#include <iostream>

using namespace std;

int main()
{
	Cuboid c1(20, 10.5, 11.5);
	Cuboid c2(11.5, 22, 9.5);
	int res = c1.compare(c2);
	if (res == 0)
	{
		cout << "第一个长方体的体积大于第二个长方体的体积" << endl;
	}
	else if (res == 1)
	{
		cout << "两个长方体的体积相等" << endl;
	}
	else
	{
		cout << "第一个长方体的体积小于第二个长方体的体积" << endl;
	}
	return 0;
}

 

[展开全文]

类的构造函数

每个类都分别定义了它的对象被初始化的方式,类通过一个或几个特殊的成员函数来控制对象的初始化过程,这些函数叫做构造函数

构造函数的任务是初始化对象的数据成员,无论何时只要类的对象被创建,就会执行构造函数。

 

声明和定义构造函数

构造函数的名称与类名相同,并且没有返回值。

声明:Student(string n, int c, int m, int e);

定义:Student::Student(string n, int c, int m, int e)

{

name=n;

chinese=c;

math=m;

english=e;

}

注意:上述代码和函数setStudent()相同,但是,程序声明对象时,会自动调用构造函数。

 

使用构造函数

C++提供了两种使用构造函数来初始化对象的方式:

1.显式地调用构造函数

Student stu1 = Student("Jane",100,90,95);

2.隐式地调用构造函数

Student stu1("Jane",100,90,95);

 

默认构造函数

默认构造函数是在未提供显示初始值时,用来创建对象的构造函数。即用于:Student stu1;

注意:当且仅当没有定义任何构造函数时,编译器才会提供默认构造函数。为类定义了构造函数后,程序员就必须为它提供默认构造函数,否则上面的声明将出错。

 

默认构造函数

定义默认构造函数的方法有两种:

1.给已有的构造函数的所有参数提供默认值。

Student(string n = "" ,int c = 0, int m = 0, int e = 0);

2.通过函数重载来定义一个没有参数的构造函数。

Student();

 

析构函数

用构造函数创建对象后,程序负责跟踪该对象,直到其过期为止。对象过期时,程序将自动调用一个特殊的成员函数,析构函数,来完成清理工作。

 

声明和定义析构函数

析构函数的名称是在类名前加上~,并且析构函数没有参数、返回值和声明类型。

声明:~Student();

定义:Student::~Student()

{

}

 

使用析构函数

类对象过期时,析构函数将自动被调用。

注意:如果程序员没有提供析构函数,编译器将隐式地声明一个默认析构函数,并在发现导致对象被删除的代码后,提供默认析构函数的定义。

 

 

//student.h

#pragma once

#ifndef STUDENT_H_
#define STDENT_H_

#include <iostream>
#include <string>

using namespace std;

//class关键字和类名
class Student
{
	//私有成员,定义数据成员,只能通过公有接口进行访问,数据隐藏
private:
	string name_;
	int chinese_;
	int math_;
	int english_;

	//共有接口
public:
	Student(string name, int chinese, int math, int english);
	Student();
	~Student();
	void setStudent(string name, int chinese, int math, int english);
	int sum(const Student &s);
	float avery(const Student &s);
	bool pass(const Student &s);
};

#endif // !STUDENT_H_

//student.cpp

#include "pch.h"
#include "student.h"

Student::Student(string name, int chinese, int math, int english)
{
	name_ = name;
	chinese_ = chinese;
	math_ = math;
	english_ = english;
}

Student::Student()
{
}

Student::~Student()
{
}

void Student::setStudent(string name, int chinese, int math, int english)
{
	name_ = name;
	chinese_ = chinese;
	math_ = math;
	english_ = english;
}

int Student::sum(const Student & s)
{
	return s.chinese_+s.math_ +s.english_;
}

float Student::avery(const Student & s)
{
	return(float)(s.chinese_ + s.math_ + s.english_) / 3;
}

bool Student::pass(const Student & s)
{
	if (s.chinese_ >= 60 && s.math_ >= 60 && s.english_ >= 60)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//18类的定义.cpp

#include "pch.h"
#include "student.h"

int main()
{
	//通过构造函数显示的初始化和隐式的初始化
	Student stu1 = Student("Sandy", 50, 120, 110);
	Student stu2("Jane", 110, 90, 100);
	Student stu3;
	/*string name1 = "Sandy";
	int chinese1 = 100;
	int math1 = 120;
	int english1 = 110;
	stu1.setStudent(name1, chinese1, math1, english1);*/
	int totalScore1 = stu1.sum(stu1);
	float averyScore1 = stu1.avery(stu1);
	bool isPassed1 = stu1.pass(stu1);
	cout << "该学生的总成绩为:" << totalScore1 << endl;
	cout << "该学生的平均成绩为:" << averyScore1 << endl;
	if (isPassed1 = true)
	{
		cout << "该学生通过了这次考试。" << endl;
	}
	else
	{
		cout << "该学生没有通过这次考试。" << endl;
	}
	return 0;
}

 

[展开全文]

对象的声明与使用

创建对象,最简单的方式是声明类变量,即Student stu1;

使用对象的成员函数和使用结构成员一样,通过成员运算符(.)来使用,即stu1.sum(stu1)。

注意:所创建的每个新对象都有自己的存储空间,用于存储其内部变量和类成员。但是同一个类的所有对象共享同一组类方法。

在OOP中,调用成员函数也被称为发送消息。

 

//student.h

#pragma once

#ifndef STUDENT_H_
#define STDENT_H_

#include <iostream>
#include <string>

using namespace std;

//class关键字和类名
class Student
{
	//私有成员,定义数据成员,只能通过公有接口进行访问,数据隐藏
private:
	string name_;
	int chinese_;
	int math_;
	int english_;

	//共有接口
public:
	void setStudent(string name, int chinese, int math, int english);
	int sum(const Student &s);
	float avery(const Student &s);
	bool pass(const Student &s);
};

#endif // !STUDENT_H_

//student.cpp

#include "pch.h"
#include "student.h"

void Student::setStudent(string name, int chinese, int math, int english)
{
	name_ = name;
	chinese_ = chinese;
	math_ = math;
	english_ = english;
}

int Student::sum(const Student & s)
{
	return s.chinese_+s.math_ +s.english_;
}

float Student::avery(const Student & s)
{
	return(float)(s.chinese_ + s.math_ + s.english_) / 3;
}

bool Student::pass(const Student & s)
{
	if (s.chinese_ >= 60 && s.math_ >= 60 && s.english_ >= 60)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//18类的定义.cpp

#include "pch.h"
#include "student.h"

int main()
{
	Student stu1;
	Student stu2;
	string name1 = "Sandy";
	int chinese1 = 100;
	int math1 = 120;
	int english1 = 110;
	stu1.setStudent(name1, chinese1, math1, english1);
	int totalScore1 = stu1.sum(stu1);
	float averyScore1 = stu1.avery(stu1);
	bool isPassed1 = stu1.pass(stu1);
	cout << "该学生的总成绩为:" << totalScore1 << endl;
	cout << "该学生的平均成绩为:" << averyScore1 << endl;
	if (isPassed1 = true)
	{
		cout << "该学生通过了这次考试。" << endl;
	}
	else
	{
		cout << "该学生没有通过这次考试。" << endl;
	}
	return 0;
}

 

[展开全文]

类方法定义

定义成员函数时,需使用作用域解析符(::)来标识函数所属的类。

类方法可以访问类的private(私有)成员。

//student.h

#pragma once

#ifndef STUDENT_H_
#define STDENT_H_

#include <iostream>
#include <string>

using namespace std;

//class关键字和类名
class Student
{
	//私有成员,定义数据成员,只能通过公有接口进行访问,数据隐藏
private:
	string name_;
	int chinese_;
	int math_;
	int english_;

	//共有接口
public:
	void setStudent(string name, int chinese, int math, int english);
	int sum(const Student &s);
	float avery(const Student &s);
	bool pass(const Student &s);
};

#endif // !STUDENT_H_

//student.cpp

#include "pch.h"
#include "student.h"

void Student::setStudent(string name, int chinese, int math, int english)
{
	name_ = name;
	chinese_ = chinese;
	math_ = math;
	english_ = english;
}

int Student::sum(const Student & s)
{
	return s.chinese_+s.math_ +s.english_;
}

float Student::avery(const Student & s)
{
	return(float)(s.chinese_ + s.math_ + s.english_) / 3;
}

bool Student::pass(const Student & s)
{
	if (s.chinese_ >= 60 && s.math_ >= 60 && s.english_ >= 60)
	{
		return true;
	}
	else
	{
		return false;
	}
}

 

[展开全文]

//student.h

#pragma once

#ifndef STUDENT_H_
#define STDENT_H_

#include <iostream>
#include <string>

using namespace std;

//class关键字和类名
class Student
{
	//私有成员,定义数据成员,只能通过公有接口进行访问,数据隐藏
private:
	string name;
	int chinese;
	int math;
	int english;

	//共有接口
public:
	void setStudent(string name, int chinese, int math, int english);
	int sum(const Student &s);
	float avery(const Student &s);
	bool pass(const Student &s);
};

#endif // !STUDENT_H_

 

[展开全文]

类的定义

类的基本思想是数据抽象和封装

抽象:对具体对象或问题进行概括,抽出这一类对象的公共性质并加以描述的过程。

数据抽象是一种依赖于接口和实现分离的编程技术。

类的接口包括用户所能执行的操作;类的实现则包括类的数据成员、负责接口实现的函数体以及定义所需的各种私有函数。

 

封装:将抽象出的数据成员、行为成员相结合,将他们视为一个整体——类。

封装实现了类的接口和实现的分离。封装后的类隐藏了它的实现细节,也就是说,类的用户只能使用接口而无法访问实现部分。

 

类声明

一般来说,类由两个部分组成:

1.类声明:以成员数据的方式描述数据部分,以成员函数(方法)的方式描述公有接口。

2.类方法定义:描述如何实现类成员函数。

通常,我们在接口放在头文件(.h)中,并将实现放在源代码文件(.cpp)中。

private:标识只能通过公共成员访问的类成员(数据隐藏),不能被使用该类的代码访问。

public:标识组成类的公共接口的类成员(抽象),在整个程序内可被访问。

公共成员函数是程序和对象的私有成员之间的桥梁,提供了对象和程序之间的接口,同时私有成员防止了程序直接访问数据。

[展开全文]

过程性编程和面向对象编程

过程性编程:就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用。

面向对象编程:就是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

 

采用过程性编程方法时,首先考虑要遵循的步骤,然后考虑如何表示这些数据。

采用面向对象编程(OOP)的方法时,首先从用户的角度考虑对象,描述对象所需的数据以及描述用户与数据交互所需要的操作。完成对接口的描述后,需要确定如何实现接口和数据存储。最后,使用新的设计方案创建出程序。

 

面向对象编程

面向对象编程的特性:

1.抽象

2.封装和数据隐藏

3.多态

4.继承

5.代码的可重用性

为了实现这些特性并将它们组合在一起,C++所作的最重要的改进是提供了

 

[展开全文]

习题4

完成程序:药品物资管理

要求:

1.利用结构体来存储目前拥有的药物的名称、种类、数量、买入价格、卖出价格。

2.利用枚举来设置药物的种类(回复mp和回复hp)。

3.编写函数来控制药物的买入和卖出,卖出价为买入价格的3/4。

4.编写函数来显示拥有的药物的剩余钱数。

5.通过输入数字来控制函数调用。

6.实现分离式编译。

 

//drug.h

#pragma once
#ifndef DRUG_H_
#define DRUG_H_
#include <string>

using namespace std;

enum Type {PlusHP,PlusMP};

struct Drug
{
	string name;
	Type type;
	int count;
	float buyPrice;
	float sellPrice;
};

const float ratio = 0.75f;
constexpr float sellPrice(Drug &d) { return d.buyPrice*ratio; }

void buyDrug(Drug &d, float& money, int num);
void sellDrug(Drug &d, float&money, int num);
void display(const Drug &d1, const Drug &d2, const float money);
string showType(const Drug &d);

#endif // !DRUG_H_

//drug.cpp

#include "pch.h"
#include "drug.h"
#include <iostream>

void buyDrug(Drug &d, float& money, int num)
{
	if (money > d.buyPrice * num)
	{
		money -= d.buyPrice*num;
		d.count += num;
		cout << "购买成功!" << endl;
	}
	else
	{
		cout << "警告:拥有的钱不足够购买" << num << "个药品!!!" << endl;
	}
}

void sellDrug(Drug &d, float&money, int num)
{
	if (d.count >= num)
	{
		d.count -= num;
		money += d.sellPrice * num;
		cout << "卖出成功!" << endl;
	}
	else
	{
		cout << "警告:没有" << num << "个药物可以售卖!!!" << endl;
	}
}

void display(const Drug &d1, const Drug &d2, const float money)
{
	cout << "目前拥有的药物:" << endl;
	cout << "1:名称:" << d1.name << "  数量:" << d1.count << "  种类:" << showType(d1) << "  购入价格:" << d1.buyPrice << "  卖出价格:" << d1.sellPrice << endl;
	cout << "1:名称:" << d2.name << "  数量:" << d2.count << "  种类:" << showType(d2) << "  购入价格:" << d2.buyPrice << "  卖出价格:" << d2.sellPrice << endl;
	cout << "拥有钱数:" << money << endl;
	cout << "显示完成!" << endl;
}

string showType(const Drug &d)
{
	switch (d.type)
	{
	case 0:
		return "PlusHP";
		break;
	case 1:
		return "PlusMP";
		break;
	default:
		break;
	}
}

//习题4.cpp

#include "pch.h"
#include "drug.h"
#include <iostream>

int main()
{
	Drug mpDrug = { "回魔药水",PlusMP,10,150,sellPrice(mpDrug) };
	Drug hpDrug = { "回血药水",PlusHP,20,100,sellPrice(hpDrug) };
	float totalMoney = 1000;

	cout << "1:购买回血药品 / 2:购买回魔药品 / 3:卖出回血药品 / 4:卖出回魔药品 / 5:输出目前拥有的药水和金钱 / 6:退出" << endl;
	cout << "请输入操作:" << endl;
	int input = 0;
	int num = 0;
	while (cin >> input && input > 0 && input < 6)
	{
		if (input == 1)
		{
			cout << "请输入购买数量:" << endl;
			if (cin >> num && num > 0)
			{
				buyDrug(hpDrug, totalMoney, num);
				cout << "请继续输入操作:" << endl;
			}
			else
			{
				cout << "输入错误,请重新输入:" << endl;
			}
		}
		else if (input == 2)
		{
			cout << "请输入购买数量:" << endl;
			if (cin >> num && num > 0)
			{
				buyDrug(mpDrug, totalMoney, num);
				cout << "请继续输入操作:" << endl;
			}
			else
			{
				cout << "输入错误,请重新输入:" << endl;
			}
		}
		else if (input == 3)
		{
			cout << "请输入卖出数量:" << endl;
			if (cin >> num && num > 0)
			{
				sellDrug(hpDrug, totalMoney, num);
				cout << "请继续输入操作:" << endl;
			}
			else
			{
				cout << "输入错误,请重新输入:" << endl;
			}
		}
		else if (input == 4)
		{
			cout << "请输入卖出数量:" << endl;
			if (cin >> num && num > 0)
			{
				sellDrug(mpDrug, totalMoney, num);
				cout << "请继续输入操作:" << endl;
			}
			else
			{
				cout << "输入错误,请重新输入:" << endl;
			}
		}
		else
		{
			display(hpDrug, mpDrug, totalMoney);
			cout << "请继续输入操作:" << endl;
		}
	}
	
	return 0;
}

 

 

 

 

 

//自写:

//Medicine.h

#pragma once
#ifndef MEDICINE_H_
#define MEDICINE_H_
#include <iostream>
#include <string>

using namespace std;

enum Sort :short
{
	PlusHP=0,
	PlusMP=1
};

struct Medicine
{
	string name;
	int count; 
	Sort sort;
	float buying_price;
	float selling_price;
};

void BuyMedicine(Medicine& med, float& money);
void SellMedicine(Medicine& med, float& money);
void DisplayAllMedicineAndMoney(Medicine med1,Medicine med2, const float money);

#endif // !MEDICINE_H_

//Medicine.cpp

#include"pch.h"
#include "Medicine.h"

void BuyMedicine(Medicine& med, float& money)
{
	int buyCount;
	cout << "请输入购买数量:" << endl;
	cin >> buyCount;

	float totalPrice = buyCount * med.buying_price;
	if (totalPrice < money && buyCount > 0)
	{
		money -= totalPrice;
		med.count += buyCount;
		cout << "购买成功!" << endl;
	}
	else
	{
		cout << "购买失败" << endl;
	}
}

void SellMedicine(Medicine& med, float& money)
{
	int sellCount;
	cout << "请输入卖出数量:" << endl;
	cin >> sellCount;

	if (med.count >= sellCount && sellCount > 0)
	{
		money += sellCount * med.selling_price;
		med.count -= sellCount;
		cout << "卖出成功!" << endl;
	}
	else
	{
		cout << "卖出失败" << endl;
	}
}

void DisplayAllMedicineAndMoney(Medicine med1, Medicine med2, const float money)
{
	cout << "目前拥有的药品:" << endl;
	cout << "1:名称:" << med1.name << "  数量:" << med1.count << "  种类:" << (med1.sort == 0 ? "PlusHP" : "PlusMP") << "  购入价格:" << med1.buying_price << "  卖出价格:" << med1.selling_price << endl;
	cout << "2:名称:" << med2.name << "  数量:" << med2.count << "  种类:" << (med2.sort == 1 ? "PlusMP" : "PlusHP") << "  购入价格:" << med2.buying_price << "  卖出价格:" << med2.selling_price << endl;
	cout << "拥有钱数:" << money << endl;
	cout << "显示完成!" << endl;
}

//习题4.cpp

#include "pch.h"
#include "Medicine.h"

int main()
{
	Medicine HP_Return = { "回血药水",20,PlusHP,100,75 };
	Medicine MP_Return = { "回魔药水",10,PlusMP,150,112.5 };
	float money = 1000.0f;

	cout << "1.购买回血药品 / 2.购买回魔药品 / 3.卖出回血药品 / 4.卖出回魔药品 / 5.输出目前拥有的药水和金钱 / 6.退出" << endl;
	bool isContinue = true;
	int inputNum;
	while (isContinue)
	{
		cout << "请输入操作:" << endl;
		cin >> inputNum;
		switch (inputNum)
		{
		case 1:
			BuyMedicine(HP_Return, money);
			break;
		case 2:
			BuyMedicine(MP_Return, money);
			break;
		case 3:
			SellMedicine(HP_Return, money);
			break;
		case 4:
			SellMedicine(MP_Return, money);
			break;
		case 5:
			DisplayAllMedicineAndMoney(HP_Return, MP_Return, money);
			break;
		case 6:
			isContinue = false;
			break;
		default:
			break;
		}
	}
}

 

[展开全文]

习题4

完成程序:药品物资管理

要求:

1.利用结构体来存储目前拥有的药物的名称、种类、数量、买入价格、卖出价格。

2.利用枚举来设置药物的种类(回复mp和回复hp)。

3.编写函数来控制药物的买入和卖出,卖出价为买入价格的3/4。

4.编写函数来显示拥有的药物的剩余钱数。

5.通过输入数字来控制函数调用。

6.实现分离式编译。

 

//drug.h

#pragma once
#ifndef DRUG_H_
#define DRUG_H_
#include <string>

using namespace std;

enum Type {PlusHP,PlusMP};

struct Drug
{
	string name;
	Type type;
	int count;
	float buyPrice;
	float sellPrice;
};

void buyDrug(Drug &d, float& money, int num);
void sellDrug(Drug &d, float&money, int num);
void display(const Drug &d1, const Drug &d2, const float money);
string showType(const Drug &d);

#endif // !DRUG_H_

//drug.cpp

#include "pch.h"
#include "drug.h"
#include <iostream>

void buyDrug(Drug &d, float& money, int num)
{
	if (money > d.buyPrice * num)
	{
		money -= d.buyPrice*num;
		d.count += num;
		cout << "购买成功!" << endl;
	}
	else
	{
		cout << "警告:拥有的钱不足够购买" << num << "个药品!!!" << endl;
	}
}

void sellDrug(Drug &d, float&money, int num)
{
	if (d.count >= num)
	{
		d.count -= num;
		money += d.sellPrice * num;
		cout << "卖出成功!" << endl;
	}
	else
	{
		cout << "警告:没有" << num << "个药物可以售卖!!!" << endl;
	}
}

void display(const Drug &d1, const Drug &d2, const float money)
{
	cout << "目前拥有的药物:" << endl;
	cout << "1:名称:" << d1.name << "  数量:" << d1.count << "  种类:" << showType(d1) << "  购入价格:" << d1.buyPrice << "  卖出价格:" << d1.sellPrice << endl;
	cout << "1:名称:" << d2.name << "  数量:" << d2.count << "  种类:" << showType(d2) << "  购入价格:" << d2.buyPrice << "  卖出价格:" << d2.sellPrice << endl;
	cout << "拥有钱数:" << money << endl;
	cout << "显示完成!" << endl;
}

string showType(const Drug &d)
{
	switch (d.type)
	{
	case 0:
		return "PlusHP";
		break;
	case 1:
		return "PlusMP";
		break;
	default:
		break;
	}
}

 

[展开全文]

分离式编译

随着程序越来越复杂,我们希望把程序的各个部分分别存储在不同的文件中。

我们可以将原来的程序分成三个部分:

1.头文件:包含结构声明和使用这些结构的函数的原型。

2.源代码文件:包含于结构有关的函数的代码。

3.源代码文件:包含调用与结构相关的函数的代码。

 

2 :函数定义

3:使用

 

分离式编译

头文件中常包含的内容:

1.函数原型

2.使用#define或const定义的符号常量

3.结构声明

4.类声明

5.模板声明

6.内联函数

 

//game.h

#pragma once

#ifndef GAME_H_
#define GAME_H_

#include <string>
using namespace std;

struct Game
{
	string gameName;
	float gameScore;
};

void inputGame(Game games[],const int size);
void sort(Game games[],const  int size);
void display(const Game games[],const int size);

const int Size = 5;

#endif // !GAME_H_

//game.cpp

#include "game.h"
#include <iostream>

void inputGame(Game games[], const int size)
{
	for (int i = 0; i < size; i++)
	{
		cout << "请输入喜爱的游戏的名称:";
		cin >> games[i].gameName;
		cout << "请输入游戏评分(10以内的小数):";
		cin >> games[i].gameScore;
	}
}

void sort(Game games[], const  int size)
{
	Game temp;
	for (int i = 0; i < size - 1; i++)
	{
		for (int j = i + 1; j < size; j++)
		{
			if (games[i].gameScore < games[j].gameScore)
			{
				temp = games[i];
				games[i] = games[j];
				games[j] = temp;
			}
		}
	}
}

void display(const Game games[], const int size)
{
	for (int i = 0; i < size; i++)
	{
		cout << i + 1 << ":" << games[i].gameName << "(" << games[i].gameScore << ")" << endl;
	}
}

//17分离式编译.cpp

#include "game.h"
#include <iostream>

int main()
{
	cout << "请输入5个你喜爱的游戏的名称,并给它们评分:" << endl;
	Game games[Size] = {};
	inputGame(games, Size);
	sort(games, Size);
	display(games, Size);
	return 0;
}

 

习题4

完成程序:药品物资管理

要求:

1.利用结构体来存储目前拥有的药物的名称、种类、数量、买入价格、卖出价格。

2.利用枚举来设置药物的种类(回复mp和回复hp)。

3.编写函数来控制药物的买入和卖出,卖出价为买入价格的3/4。

4.编写函数来显示拥有的药物的剩余钱数。

5.通过输入数字来控制函数调用。

6.实现分离式编译。

 

[展开全文]

函数指针

与数据项类似,函数也有地址。函数的地址是存储其机器语言代码内存的开始地址。可以将地址作为函数的参数,从而使第一个函数能够找到第二个函数,并运行它。

函数指针指向的是函数而非对象。

想要声明一个可以指向函数的指针,只需要用指针替换函数名即可。

bool lengthCompare(const string &,const string &); //函数

bool (*pf)(const string &,const string &); //函数指针

 

函数指针

bool (*pf)(const string &,const string &);

pf是一个指向函数的指针,其中该函数的参数是两个const string 的引用,返回值是布尔类型。

注意:*pf两端的括号必不可少,如果省略括号,就变成了一个返回值为bool指针的函数,而不是指向函数的指针

当我们把函数名作为一个值使用时,该函数自动地转换成指针。还可以直接使用指向函数的指针调用该函数

 

#include <iostream>
#include <string>

using namespace std;

bool lengthCompare(const string &s1, const string &s2);
void display(const string &s1, const string&s2, bool(*p)(const string &, const string &));

int main()
{
	string name1 = "Sandy";
	string name2 = "Jane";
	
	//bool res = lengthCompare(name1, name2);

	//定义一个函数指针并给它赋值,pf是指向函数lengthCompare的指针
	bool(*pf)(const string &, const string &);
	pf = lengthCompare;
	/*res = pf(name1, name2);
	if (res == true)
	{
		cout << name1 << "的长度大于" << name2 << endl;
	}
	else
	{
		cout << name1 << "的长度小于" << name2 << endl;
	}*/

	//将pf作为实参传递给函数display
	display(name1, name2, pf);
	return 0;
}

//对比两个字符串的长度
bool lengthCompare(const string &s1, const string &s2)
{
	return size(s1) > size(s2) ? true : false;
}

//将函数指针作为参数传递给另外一个函数,可以直接在这个函数中通过函数指针指向的函数
void display(const string &s1, const string&s2, bool(*p)(const string &, const string &))
{
	if (p(s1, s2) == true)
	{
		cout << s1 << "的长度大于" << s2 << endl;
	}
	else
	{
		cout << s1 << "的长度小于" << s2 << endl;
	}
}

[展开全文]

 

函数与string对象

与结构相似,可以将string对象作为完整的实体进行传递。string对象也可以像基本类型那样,作为参数传递,并作为返回值使用。

如果需要多个字符串,可以声明一个string对象的数组。

 

#include <iostream>
#include <string>

using namespace std;

void fill_games(string name[], int n);
void print_games(const string name[], int n);

int main()
{
	const int size = 5;
	cout << "请输入" << size << "个你喜欢的游戏的名称:" << endl;
	string gameNames[size] = {};
	fill_games(gameNames, size);
	print_games(gameNames, size);
	return 0;
}

void fill_games(string name[], int n)
{
	for (int i = 0; i < n; i++)
	{
		getline(cin, name[i]);
	}
}

void print_games(const string name[], int n)
{
	for (int i = 0; i < n; i++)
	{
		cout << i + 1 << ":" << name[i] << endl;
	}
}

 

[展开全文]

 

函数与结构体

使用结构编程时,最直接的方式是像处理基本类型那样来处理结构,也就是说,将结构作为参数传递,并在需要时将结构用作返回值使用。

如果结构非常大,则复制结构将增加内存要求,降低系统运行的速度,这种情况下,应使用指针来访问结构的内容,或按引用进行传递。

 

#include <iostream>

using namespace std;

struct WorkTime
{
	int hours;
	int mins;
};

const int Mins_per_hour = 60;

WorkTime sum(WorkTime t1, WorkTime t2);

int main()
{
	WorkTime morning = { 2,40 };
	WorkTime afternoon = { 6,40 };
	WorkTime day = sum(morning, afternoon);
	cout << "一天一共工作了:" << day.hours << "小时," << day.mins << "分钟。" << endl;
	return 0;
}

//结构体在函数中可以和基本类型一样使用,作为参数传递或者作为返回值返回
//结构体较大时,为了避免复制副本,可以使用指针和引用类型
WorkTime sum(WorkTime t1, WorkTime t2)
{
	WorkTime total;
	total.mins = (t1.mins + t2.mins) % Mins_per_hour;
	total.hours = t1.hours + t2.hours + (t1.mins + t2.mins) / Mins_per_hour;
	return total;
}

[展开全文]

习题3

完成程序:射击分数显示

要求:

1.要求用户输入最多10个射击分数,并将它们存储在一个数组中。

2.输入负数提前完成输入。

3.使用3个数组处理函数分别进行输入、显示和计算平均分数的操作。

4.显示所有分数和平均分数。

 

//老师代码:

#include <iostream>

using namespace std;

int fill_scores(int arr[], const int n);
void print_scores(int arr[], int n);
float average(int arr[], int n);

int main()
{
	const int maxSize = 10;
	int scores[maxSize] = {};
	//调用函数,填充数组并得到数组的元素的个数
	int size = fill_scores(scores, maxSize);
	print_scores(scores, size);
	float ave = average(scores, size);
	cout << "平均分数为:" << ave;
	return 0;
}

int fill_scores(int arr[], const int n)
{
	int temp;
	int i = 0;
	cout << "请输入最多10个射击成绩(输入负数则提前结束输入):" << endl;
	//1,判断输入的数字的个数是否小于等于10个
	while (i < n)
	{
		cin >> temp;
		//判断数据是否大于0,大于0的话,继续接受,小于0的话,停止接收
		if (temp >= 0)
		{
			arr[i] = temp;
			i++;
		}
		else
		{
			break;
		}
	}
	if (i == 9)
	{
		cout << "已输入10个分数。" << endl;
	}
	//将输入的数字的个数返还
	return i;
}

void print_scores(int arr[], int n)
{
	for (int i = 0; i < n; i++)
	{
		cout <<"分数"<< i + 1 << ":" << arr[i] << endl;
	}
}

float average(int arr[], int n)
{
	float res = 0;
	for (int i = 0; i < n; i++)
	{
		res += arr[i];
	}
	return res / n;
}

//自写代码

#include <iostream>

using namespace std;
void InputShootScore(int arr[], int size, int&inputRightNum);
void PrintShootScore(const int arr[], int inputRightNum);
float CalculateShootAverageScore(const int arr[], int inputRightNum);

int main()
{
	const int size = 10;
	int inputRightNum = 0;
	int arr[size] = {};
	cout << "请输入最多10个射击成绩(输入负数提前结束输入):" << endl;
	InputShootScore(arr, size,inputRightNum);
	cout << "射击分数为:" << endl;
	PrintShootScore(arr, inputRightNum);
	cout<<"平均分数为:"<<CalculateShootAverageScore(arr, inputRightNum);

	return 0;
}

void InputShootScore(int arr[],int size,int&inputRightNum)
{
	int temp;
	inputRightNum = 0;
	for (int i = 0; i < size; i++)
	{
		cin >> temp;
		if (temp < 0)
		{
			break;
		}
		arr[i] = temp;
		inputRightNum++;
	}
}

void PrintShootScore(const int arr[], int inputRightNum)
{
	for (int i = 0; i < inputRightNum; i++)
	{
		cout << "分数" << (i + 1) << ":" << arr[i] << endl;
	}
}

float CalculateShootAverageScore(const int arr[], int inputRightNum)
{
	int totalScore = 0;
	for (int i = 0; i < inputRightNum; i++)
	{
		totalScore += arr[i];
	}
	return float(totalScore) / inputRightNum;
}

 

[展开全文]

函数与数组

填充数组或修改数组:由于接受数组名参数的函数访问的是原始数组(使用指针访问),而不是其副本,因此可以通过调用该函数将值赋给数组元素,或是修改数组元素的值。

显示数组以及保护数组:为了确保显示函数不修改原始数组,可在声明形参时使用关键字const

二维数组int sum(int ar2[][4],int size);

 

填充cin

 

 

#include <iostream>
#include <string>

using namespace std;

int sum_arr(const int arr[], int n);
void fill_arr(int arr[], int n);
void ratio(int arr[], int n, int sum);
void print_arr(const int arr[], int n);

int main()
{
	const int size = 6;
	int student1[size] = { 120,110,100,90,85,95 };
	int totalScore = sum_arr(student1, size);
	cout << "该名学生的总成绩为:" << totalScore << endl;

	int student2[size]= {};
	fill_arr(student2, size);
	totalScore = sum_arr(student2, size);
	cout << "该学生的各科成绩为:" << endl;
	print_arr(student2, size);
	ratio(student2, size, totalScore);
	cout << "各科成绩所占百分比(%):" << endl;
	print_arr(student2, size);

	return 0;
}

//arr时一个指针,指向数组的第一个元素,const int类型,所以不能修改数组内的值。
//n是数组的大小
//在函数体内,可以将arr直接当做数组名用,*arr和arr[]的意义相同。
int sum_arr(const int arr[], int n)
{
	int res = 0;
	//arr[1] = 1; //出错
	for (int i = 0; i < n; i++)
	{
		res += arr[i];
	}
	return res;
}

void fill_arr(int arr[], int n)
{
	cout << "请输入该学生的成绩(语数外物化生):" << endl;
	int temp;
	for (int i = 0; i < n; i++)
	{
		cin >> temp;
		arr[i] = temp;
	}
}

void ratio(int arr[], int n, int sum)
{
	for (int i = 0; i < n; i++)
	{
		arr[i] = arr[i] * 100 / sum;
	}
}

void print_arr(const int arr[], int n)
{
	for (int i = 0; i < n; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

 

 

习题3

完成程序:射击分数显示

要求:

1.要求用户输入最多10个射击分数,并将它们存储在一个数组中。

2.输入负数提前完成输入。

3.使用3个数组处理函数分别进行输入、显示和计算平均分数的操作。

4.显示所有分数和平均分数。

 

 

[展开全文]

函数和数组

数组作为参数:int sum_arr(int arr[],int n);

1.arr是数组名,但arr实际上并不是数组,而是一个指针,指向数组的第一个元素。但是再编写函数的奇遇部分时,可以将arr看作是数组。

2.当且仅当用于函数头或函数原型中,int *arr和int arr[]的含义才是相同的。他们都意味着arr时一个int指针。然而,数组表示法提醒用户,arr不仅指向int,还指向int数组的第一个int。

 

#include <iostream>
#include <string>

using namespace std;

int sum_arr(const int arr[], int n);

int main()
{
	const int size = 6;
	int student1[size] = { 120,110,100,90,85,95 };
	int totalScore = sum_arr(student1, size);
	cout << "该名学生的总成绩为:" << totalScore << endl;
	return 0;
}

//arr时一个指针,指向数组的第一个元素,const int类型,所以不能修改数组内的值。
//n是数组的大小
//在函数体内,可以将arr直接当做数组名用,*arr和arr[]的意义相同。
int sum_arr(const int arr[], int n)
{
	int res = 0;
	//arr[1] = 1; //出错
	for (int i = 0; i < n; i++)
	{
		res += arr[i];
	}
	return res;
}

 

函数与数组

填充数组或修改数组:由于接受数组名参数的函数访问的是原始数组(使用指针访问),而不是其副本,因此可以通过调用该函数将值赋给数组元素,或是修改数组元素的值。

显示数组以及保护数组:为了确保显示函数不修改原始数组,可在声明形参时使用关键字const

二维数组int sum(int ar2[][4],int size);

[展开全文]

函数重载

如果同一作用域内的几个函数名字相同但形参列表不同,我们称之为重载函数

void print(const char *cp);

void print(const int *beg,const int *end);

void print(const int ia[],size_t size);

这些函数接受的形参类型不一样,但是执行的操作非常类似。当调用这些函数时,编译器会根据传递的实参类型推断想要的是哪个函数。

 

 

#include <iostream>

using namespace std;

//重载函数,名称相同但是参数列表不同的函数,调用时,系统会根据我们传递的实参来选择调用的函数。
void print(const char *cp);
void print(const int *beg, const int *end);
void print(const int ia[], size_t size);

int main()
{
	char c = 'a';
	//传递的实参是char类型的指针,所以会调用第一个函数
	print(&c);

	const size_t size = 5;
	int arr[size] = { 2,3,3 };
	//传递的实参是两个int类型的指针,所以会调用第二个函数
	print(&arr[2], &arr[size - 1]);
	//传递的实参是数组名和一个size_t类型的值,所以会调用第三个函数
	print(arr, size);
	//传递的实参是数组名,但是没有和它相对应的参数列表的函数定义,所以会出错
	//print(arr);
	return 0;
}

void print(const char *cp)
{
	cout << "1: " << *cp << endl;
}

void print(const int *beg, const int *end)
{
	int length = end - beg;
	for (int i = 0; i <= length; i++)
	{
		cout << "2: " << *(beg + i) << endl;
	}
}

void print(const int ia[], size_t size)
{
	for (int i = 0; i < size; i++)
	{
		cout << "3: " << ia[i] << endl;
	}
}

[展开全文]

constexpr函数

constexpr函数:是指能用于常量表达式的函数,即可以在编译时计算其返回值的函数。

常量表达式是指值不会改变且在编译过程就能得到计算结果的表达式。

 

const expression

 

constexpr函数

注意:

1.函数中只能有一个return语句。

2.返回值必须是字面值类型(算术类型、引用、指针属于字面值类型)。

3.参数必须是字面值类型(自定义类、IO库、string类型不属于字面值类型)。

4.constexpr函数被隐式地指定为内联函数。

5.允许递归

 

#include <iostream>

using namespace std;

//常量表达式函数
constexpr int fact(int n)
{
	return n == 1 ? 1 : n * fact(n - 1);
}
//常量表达式
constexpr int num = 5;

int main()
{
	//在编译期间可以计算结果并返回结果
	cout << fact(num) << endl;
	cout << fact(3) << endl;

	//实参为变量时,在程序运行期间计算并返回结果
	int i = 8;
	int res = fact(i);
	cout << res << endl;
	return 0;
}

[展开全文]

内联函数是C++为提高程序运行速度所作的一项改进。

内联函数的编译代码与其他程序代码“内联”起来了,也就是说,编译器将使用相应的函数代码替代函数调用。

对于内联代码,程序无需跳到另一个位置处执行代码,再跳回来。因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。

 

内联函数

内联函数的使用方法:在函数声明或函数定义前加上关键字 inline

通常的做法是省略原型,将这个定义放在本应提供原型的地方。

注意:内联函数不能递归

 

#include <iostream>

using namespace std;
inline int sum(int a, int b) { return a + b; }

int main()
{
	int res = sum(20, 45);
	cout << res << endl;
	return 0;
}

[展开全文]