函数的默认参数
在C++中,函数的形参列表中的形参是可以有默认值的
语法:返回值类型 函数名 (参数=默认值){}
//如果某个位置已经有了默认参数,则从这个位置往后,从左到右都必须要有默认值
//int func2(int a, int b = 10, int c,int d){} 错误
//int func2(int a, int b = 10, int c = 10,int d = 10){} 正确
//int func2(int a, int b, int c, int d = 10) {} 正确
//如果函数声明有默认参数,函数实现就不能有默认参数(声明和实现只能有一个有默认参数)
int func2(int a = 10, int b = 10);//函数声明
int func2(int a, int b = 20) //函数实现//这里打出来的代码不会显示有错,但运行会出错
{//错误 C2572 “func2” : 重定义默认参数: 参数 1
return a + b;
}
int func(int a, int b = 50, int c = 10) {
return a + b + c;
}
int main() {
//如果我们自己传入数据,就用传入的数据,如果没有,就用默认值
cout << func(10) << endl;//10+50+10=70
cout << func(10, 20) << endl;//10+20+10=40
cout << func(10, 20, 30) << endl;//10+20+30=60
return 0;
}
函数占位参数
C++中参数的形参列表里可以有占位参数,用来占位,调用函数时必须填补该位置
语法:返回值类型 函数名 (数据类型){}
//占位参数,可以有默认参数,如:void func(int a, int = 10){}
void func(int a,int) {
cout << "this is func" << endl;
}
int main() {
func(10,10);//占位参数int没有值,因此这里需要传入两个参数填补占位参数,不然会报错
//如果是第一行是 void func(int a, int = 10),这里就可以写成 func(10);
return 0;
}
函数重载
函数名可以相同,提高复用性
函数重载满足条件:
- 同一个作用域下
- 函数名称相同
- 函数参数类型不同,或者参数个数不同,或者参数顺序不同
注意:函数的返回值不可以作为函数重载的条件
//main函数外面都是全局作用域
//函数名称相同
void func() { cout << "函数 1 " << endl; }//0参数
void func(int a) { cout << "函数 2 " << endl; }// 1 个参数,函数 1 和 2 的参数个数不同
void func(double a) { cout << "函数 3 " << endl; }//函数 2 和 3 的参数类型不同
void func(int a, double b) { cout << "函数 4 " << endl; }
void func(double a, int b) { cout << "函数 5 " << endl; }//函数 4 和 5 的参数顺序不同
//int func(double a, int b) { cout << "函数 5 " << endl; }//返回值不能作为重载条件
int main() {
func();//打印 函数 1
func(10);//打印 函数 2
func(3.14);//打印 函数 3
func(3.14,10);//打印 函数 5
func(10,3.14);//打印 函数 4
func(0.11, 10);//打印 函数 5
return 0;
}
函数重载注意事项
- 引用可以作为重载条件
- 函数重载碰到函数默认参数
void func1(int &a) { cout << "函数 1 " << endl; }
void func1(const int &a) { cout << "函数 2 " << endl; }
//重载遇到默认参数,出现二义性,尽量避免
void func2(int a, int b = 20) { cout << "函数 3 " << endl; }
void func2(int a) { cout << "函数 4 " << endl; }
int main() {
int a = 10;//变量 a 可读可写
func1(a);//打印 函数 1
//因为变量可读可写,而函数 2 加了const,是只读状态,所以调用函数 1
func1(10);//打印 函数 2
//int &a = 10;不合法 const int &a = 10;合法
func2(10, 30);//打印 函数 3
//func2(10); //此行报错,因为这样写函数 3 和 4 都可被调用
return 0;
}
类和对象——封装
类中的属性和行为统一称为成员
- 属性(或称为 成员属性、成员变量)
- 行为(或称为 成员函数、成员方法)
C++面向对象的三大特性:封装、继承、多态
C++中,万事万物皆为对象,对象上有其属性和行为
对象:人,属性:姓名、性别、身高、年龄……,行为:走路、跑步、吃饭……
对象:车,属性:轮胎、方向盘、车灯……,行为:载人、放音乐、拉货……
具有相同性质的对象,可以抽象称为类,如人属于人类,车属于车类
封装的意义:
- 将属性和行为作为一个整体,表现生活中的事物
- 将属性和行为加以权限控制
封装意义一:
设计类时,属性和行为写在一起,表现事物
语法:class 类名{ 访问权限:属性 / 行为 };
示例一:设计一个圆类,求圆的周长
//圆周长公式:2 * PI * 半径
const double PI = 3.14;
class Yuan {//class代表设计一个类,类后面跟着类名称
public:
int r;//属性,半径
double C() {//行为,计算周长
return 2 * PI * r;
}
};
int main() {
//通过圆类Yuan,创建具体的圆(对象)
Yuan c1;//实例化(通过一个类,创建一个对象的过程)
c1.r = 10;//给圆对象的属性赋值
cout << "圆的周长为:" << c1.C() << endl;//打印 圆的周长为:62.8
return 0;
}
示例二:设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号
class Student {
public://类中的属性和行为统一称为成员
//属性(或称为 成员属性、成员变量)
string S_Name;//姓名是字符串,用string
int S_Id;
//行为(或称为 成员函数、成员方法)
void showStudent() {
cout << "姓名:" << S_Name << " 学号:" << S_Id << endl;
}
//通过行为给属性赋值
void setName(string name) {
S_Name = name;
}
void setId(int id) {
S_Id = id;
}
};
int main() {
Student s1;//实例化对象
s1.S_Name = "星星";//给s1对象进行属性赋值
s1.S_Id = 1;
s1.showStudent();
Student s2;//实例化对象
s2.setName("月亮");//调用赋值函数
s2.setId(2);
s2.showStudent();
}
封装意义二:
类在设计时,可以把属性和行为放在不同的权限下,加以控制
访问权限有三种:
public —— 公共权限 类内可以访问 类外可以访问
protected —— 保护权限 类内可以访问 类外不可以访问(继承,儿子可以访问父亲保护内容)
private —— 私有权限 类内可以访问 类外不可以访问(继承,儿子不可以访问父亲私有内容)
class Person {
public:
string P_Name;
protected:
string P_Car;//车
private:
int P_Pwd;//银行卡密码
public:
void func() {//公共函数
P_Name = "李四";
P_Car = "奥迪";
P_Pwd = 123456;
}
};//Person类大括号内是类内
int main() {
Person p1;//实例化具体对象
p1.P_Name = "张三";
p1.P_Car = "宝马";//错误 “Person::P_Car”: 无法访问 protected 成员(在“Person”类中声明)
p1.P_Pwd = 000000;//错误 “Person::P_Pwd”: 无法访问 private 成员(在“Person”类中声明)
}
struct和class区别
在C++中struct和class唯一的区别是默认的访问权限不同
- struct默认权限为公共
- class默认权限为私有
class C1 {
int A;
};
struct C2 {
int A;
};
int main() {
C1 c1;
c1.A = 10;//错误“C1::A”: 无法访问 private 成员(在“C1”类中声明)
C2 c2;
c2.A = 10;
}
成员属性设置为私有
- 可以自己控制读写权限
- 对于写的权限,可以检测数据有效性
class Person {
public://创建公共接口
void setName(string name) {//设置姓名 写
P_Name = name;
}
string getName() {//获取姓名 读
return P_Name;
}
int getAge() {//获取年龄,只读
P_Age = 10;//初始化年龄
return P_Age;
}
//如果不加setAge函数,年龄就只能是只读状态
//void setAge(int age) {//设置年龄
// if (age < 0 || age>150) {
// cout << "您的年龄不符合规定!" << endl;
// return;
// }
//}
void setLover(string lover) {//设置爱人 只写
P_Lover = lover;
}
private:
string P_Name;//赋予可读可写权限
int P_Age;//赋予只读权限
string P_Lover;//赋予只写权限
};
int main() {
Person p;
p.setName("李四");//写
cout << "Name:" << p.getName() << endl;//读
p.P_Age = 10;//不可 写,报错
cout << "Age:" << p.getAge() << endl;
p.setLover("星星");
cout << "Lover:" << p.getLover() << endl;//不可 读, 报错
}
案例一:设计立方体类(Cube)
求立方体面积和体积
分别用全局函数和成员函数判断两个立方体是否相等
//立方体类
class Cube {
public:
void setL(int l) {//设置长
m_L = l;
}
int getL() {//获取长
return m_L;
}
void setW(int w) {//设置宽
m_W = w;
}
int getW() {//获取宽
return m_W;
}
void setH(int h) {//设置高
m_H = h;
}
int getH() {//获取高
return m_H;
}
int calculateS() {
return 2 * m_L * m_W + 2 * m_W * m_H + 2 * m_L * m_H;
}
int calculateV() {
return m_L * m_W * m_H;
}
//成员函数判断是否相等
bool isSameByClass(Cube &c) {
if (m_L == c.getL() && m_W == c.getW() && m_H == c.getH()) {
return true;
}
return false;
}
private:
int m_L;//长
int m_W;//宽
int m_H;//高
};
bool isSame(Cube &c1, Cube &c2) {//全局函数判断是否相等
if (c1.getL() == c2.getL() && c1.getW() == c2.getW() && c1.getH() == c2.getH()) {
return true;
}
else
return false;
}
int main() {
Cube c1;//创建立方体对象
c1.setL(10);
c1.setW(10);
c1.setH(10);
cout << "立方体c1的面积:" << c1.calculateS() << endl;
cout << "立方体c1的体积:" << c1.calculateV() << endl;
Cube c2;//第一个立方体
c2.setL(10);
c2.setW(10);
c2.setH(10);
cout << "立方体c2的面积:" << c2.calculateS() << endl;
cout << "立方体c2的体积:" << c2.calculateV() << endl;
bool ret = isSame(c1, c2);
if (ret) {
cout << "c1和c2是相等的" << endl;
}
else {
cout << "c1和c2是不相等的" << endl;
}
ret = c1.isSameByClass(c2);
if (ret) {
cout << "成员函数判断:c1和c2是相等的" << endl;
}
else {
cout << "成员函数判断:c1和c2是不相等的" << endl;
}
}
案例二:点和圆的关系(计算点到圆心的距离)
设计一个圆类(Cricle)一个点类(Point),判断点和圆的关系
圆心(x1,y1),点(x2,y2)
写法一:
class Point {//点类数据类型
public:
void setX(int x) {
m_X = x;
}
int getX() {
return m_X;
}
void setY(int y) {
m_Y = y;
}
int getY() {
return m_Y;
}
private:
int m_X;
int m_Y;
};
class Cricle {//圆类
public:
void setR(int r) {
m_R = r;
}
int getR() {
return m_R;
}
void setCenter(Point center) {
m_Center = center;
}
Point getCenter() {
return m_Center;
}
private:
int m_R;//半径
//在类中,可以让另一个类作为本类中的成员
Point m_Center;//圆心
};
//判断点和圆关系函数
void isInCricle(Cricle &c, Point &p) {
int distance =
(c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) +
(c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
int rDistance = c.getR() * c.getR();
if (distance == rDistance) {
cout << "点在圆上" << endl;
}
else if (distance > rDistance) {
cout << "点在圆外" << endl;
}
else {
cout << "点在圆内" << endl;
}
}
int main() {
Cricle c;//圆
c.setR(10);//半径为10
Point center;//圆心
center.setX(10);
center.setY(0);
c.setCenter(center);
Point p;//点
p.setX(10);
p.setY(10);
isInCricle(c, p);//调用判断函数
}
写法二(分开写):
源.cpp
#include<iostream>
using namespace std;
#include"Point.h"
#include"Cricle.h"
//判断点和圆关系函数
void isInCricle(Cricle &c, Point &p) {
int distance =
(c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) +
(c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
int rDistance = c.getR() * c.getR();
if (distance == rDistance) {
cout << "点在圆上" << endl;
}
else if (distance > rDistance) {
cout << "点在圆外" << endl;
}
else {
cout << "点在圆内" << endl;
}
}
int main() {
Cricle c;//圆
c.setR(10);//半径为10
Point center;//圆心
center.setX(10);
center.setY(0);
c.setCenter(center);
Point p;//点
p.setX(10);
p.setY(10);
isInCricle(c, p);//调用判断函数
}
point.h
#pragma once
#include<iostream>
using namespace std;
class Point {//点类
public:
void setX(int x);
int getX();
void setY(int y);
int getY();
private:
int m_X;
int m_Y;
};
point.cpp
#include"point.h"
void Point::setX(int x) {
m_X = x;
}
int Point::getX() {
return m_X;
}
void Point::setY(int y) {
m_Y = y;
}
int Point::getY() {
return m_Y;
}
cricle.h
#pragma once
#include<iostream>
using namespace std;
#include"point.h"
class Cricle {//圆类
public:
void setR(int r);
int getR();
void setCenter(Point center);
Point getCenter();
private:
int m_R;//半径
//在类中,可以让另一个类作为本类中的成员
Point m_Center;//圆心
};
cricle.cpp
#include"cricle.h"
void Cricle::setR(int r) {
m_R = r;
}
int Cricle::getR() {
return m_R;
}
void Cricle::setCenter(Point center) {
m_Center = center;
}
Point Cricle::getCenter() {
return m_Center;
}