九、引用
作用:给变量取别名。
语法:数据类型 &别名 = 原名;
可以通过别名修改变量的值。
9.1、引用的注意事项:
引用必须初始化,且初始化后不可改变。(不能作为其他变量的别名)
#include<iostream>
using namespace std;
int main()
{
int a = 10;
int c = 20;
//int& b; 引用必须初始化
int& d = a;
d = c;//这只是赋值操作,会改变a的值,d还是a的别名
cout << "a=" << a << ",d=" << d << ",c=" << c << endl;
return 0;
9.2、引用做函数参数
函数传参时,可以利用引用技术让形参修饰实参,可以简化指针的使用。
示例:交换函数
#include<iostream>
using namespace std;
//值传递
void myswap01(int a, int b)
{
int temp;
temp = a;
a = b;
b = temp;
}
//地址传递
void myswap02(int *a, int *b)
{
int temp= *a;
*a = *b;
*b = temp;
}
//引用传递
void myswap03(int &a, int &b)
{
int temp;
temp = a;
a = b;
b = temp;
}
int main()
{
int a = 10;
int b = 20;
myswap01(a, b);//值传递,实参不会改变
cout << "a = " << a << endl;
cout << "b = " << b << endl;
myswap02(&a, &b);//地址传递,实参发生改变
cout << "a = " << a << endl;
cout << "b = " << b << endl;
myswap03(a, b);//引用传递,实参发生改变
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}
9.3、引用做函数返回值
1、不要返回局部变量的引用。
2、函数的调用可以作为左值。
#include<iostream>
using namespace std;
int& test01()
{
int a = 10;//局部变量存放在栈区
return a;
}
int& test02()
{
static int a = 10;//静态变量存放在全局区
return a;
}
int main()
{
int& ref = test01();
cout << "ref = " << ref << endl;
cout << "ref = " << ref << endl;//a的内存释放,数据错误
int& ref2 = test02();
cout << "ref2 = " << ref2 << endl;
cout << "ref2 = " << ref2 << endl;//a的内存没有释放
test02() = 1000;//通过引用,修改静态变量的值,函数调用做了左值
cout << "ref2 = " << ref2 << endl;
cout << "ref2 = " << ref2 << endl;
}
9.4、引用的本质:
引用的本质在C++内部实现是一个指针常量。
#include<iostream>
using namespace std;
void func(int& ref)
{
ref = 100;//ref是引用,转换为*ref=100;
}
int main()
{
int a = 10;
int& ref = a;
//转换为int *const ref = &a;指针常量指向不可修改
ref = 20;//引用自动转换为 *ref = 20;
cout << "a = " << a << endl;
cout << "ref = " << ref << endl;
func(a);
cout << "a = " << a << endl;
cout << "ref = " << ref << endl;
return 0;
}
9.5、常量引用:
常量引用作用主要是用来修饰形参,防止误操作。
#include<iostream>
using namespace std;
void showValue(const int& val)
{
//val = 1000;//加入const后,无法通过val修改a的值
cout << val << endl;
}
int main()
{
//int a = 10;
//加上const后,编译器将代码修改为int temp = 10;const int &ref = temp;
const int& ref = 10;
//ref = 20;加入const后变为只读,不可修改。
int a = 100;
showValue(a);
return 0;
}
十、函数高级:
10.1、函数的默认参数:
在C++中,函数的形参列表中形参可以是有默认值的。
语法: 数据类型 函数名(形参名= 默认参数)
#include<iostream>
using namespace std;
int func(int a, int b=20, int c=30)
{
return a + b + c;
}
int main()
{
cout << func(10) << endl;//默认参数可以不传
cout << func(10,30) << endl;//传了默认参数会覆盖默认参数的值
return 0;
}
注意事项:
1、某个位置已经有了默认参数,从这个位置往后,从左到右,都必须有默认值
void func(int a,int b = 10,int c)
{
return a+b+c;
}//这种写法是错误的,b有了默认参数,b右边的所有参数必须要有默认参数
2、如果函数声明有默认参数,函数实现不能有默认参数。
10.2、函数占位参数
C++中函数的形参列表里可以有占位参数,用来做占位,调用参数时必须填补该位置。
#include<iostream>
using namespace std;
void func(int a, int)
{
cout << "this is func" << endl;
}
int main()
{
func(10, 10);
return 0;
}
占位参数也可以有默认参数
#include<iostream>
using namespace std;
void func(int a, int =10)
{
cout << "this is func" << endl;
}
int main()
{
func(10);
return 0;
}
10.3、函数重载
作用:函数名可以相同,提高复用性。
函数重载满足条件:
- 同一个作用域下
- 函数名称相同
- 函数参数类型不同或者个数不同或者顺序不同。
- 函数的返回值不可以作为函数重载的条件。
#include<iostream>
using namespace std;
void func()
{
cout << "this is func()" << endl;
}
void func(int a)
{
cout << "this is func(int a)" << endl;
}
void func(double a)
{
cout << "this is func(double a)" << endl;
}
void func(int a,double b)
{
cout << "this is func(int a,double b)" << endl;
}
void func(double a, int b)
{
cout << "this is func(double a,int b)" << endl;
}
int main()
{
func();
func(10);
func(3.14);
func(10, 3.14);
func(3.14, 10);
return 0;
}
注意事项:
- 引用是函数重载条件:
#include<iostream> using namespace std; void func(int& a) { cout << "func (int &a)" << endl; } void func(const int& a) { cout << "func (const int &a)" << endl; } int main() { int a = 10; func(a);//调用func(int &a)函数 func(10);//调用func(const int &a)函数 return 0; }
- 函数重载与默认参数:
函数重载遇到默认参数会出现二义性。
#include<iostream> using namespace std; void func2(int a,int b=10) { cout << "func2 (int a,int b=10)" << endl; } void func2(int a) { cout << "func2 (int a)" << endl; } int main() { func2(10,10);//两个参数可以用 //func2(10)//一个参数无法确认是哪个函数 return 0; }
十、类和对象
C++面向对象的三大特性:封装、继承、多态
C++认为万事万物都是对象,对象上有其属性和行为。
具有相同性质的对象,可以抽象为类
10.1、封装
封装的意义:
- 将属性和行为作为一个整体,表现生活中的事物——在设计类的时候,将属性和行为写在一起,表现事物。
语法:class 类名{访问权限:属性/行为};
示例:设计一个圆,求圆的周长。
实例化:通过一个类创造一个对象。
#include<iostream> #define PI 3.14 using namespace std; //定义一个圆类 class Circle { //访问权限 public: //属性 double m_r;//半径 //行为————用函数表示行为 //获取圆的周长 double calculateZC() { return 2 * PI * m_r; } }; int main() { //通过圆类创造具体的圆 Circle c1; //给属性进行赋值 c1.m_r = 10; cout << "圆c1的周长为:" << c1.calculateZC() << endl; return 0; }
示例二:设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号(行为)。
#include<iostream> #include<string> using namespace std; class student { public: string name; int s_id; void showstudent() { cout << "学生的姓名是:" << name; cout << ",学生的学号是:" << s_id << endl; } }; int main() { student s1; s1.name = "zxx"; s1.s_id = 1; s1.showstudent(); return 0; }
可以通过行为给属性赋值。
#include<iostream> #include<string> using namespace std; class student { public: string name; int s_id; void showstudent() { cout << "学生的姓名是:" << name; cout << ",学生的学号是:" << s_id << endl; } void setName(string c) { name = c; } }; int main() { student s1; s1.setName("zxx"); s1.s_id = 1; s1.showstudent(); return 0; }
- 将属性和行为加以权限控制
权限有三种:
- public:公共权限
- protected:保护权限
- private:私有权限
#include<iostream> #include<string> using namespace std; class person { public://类内可以访问,类外不可以访问 string name; protected://类内可以访问,类外不可以访问,可以继承(儿子可以访问) string car; private://类内可以访问,类外不可以访问,不可以继承(儿子不可以访问) int password; public: void func() { name = "zxx"; car = "biyadi"; password = 123456; } void print() { cout << name << car << password << endl; } }; int main() { person p1; p1.name = "ww"; //p1.car = "benchi";保护权限内容在类外访问不到。 //p1.password = 111111;私有权限内容在类外访问不到。 p1.func(); p1.print(); return 0; }
类中的属性和行为都成为成员。
10.1.1、struct和class的区别:
class和struct唯一的区别在于默认的访问权限不同,struct默认权限为公共,class默认权限为私有。
10.1.2、成员属性私有化
优点:
- 将所有成员属性设为私有,可以自己控制读写权限
- 对于写权限,可以检测数据的有效性
#include<iostream>
#include<string>
using namespace std;
class person
{
private:
string name;//可读可写
int age;//只读
string lover;//只写
public:
//写姓名
void setname(string n)
{
name = n;
}
//读姓名
string getname()
{
return name;
}
//读年龄
int getage()
{
age = 0;//初始化为0岁
return age;
}
//写情人
void setlover(string l_n)
{
lover = l_n;
}
};
int main()
{
person p;
//无法直接访问属性,只能通过行为来获取和设置信息
p.setname("ww");
cout << "姓名为:" << p.getname() << endl;
cout << "年龄为:" << p.getage() << endl;
p.setlover("甘乐");
return 0;
}
检测数据有效性:
#include<iostream>
#include<string>
using namespace std;
class person
{
private:
string name;//可读可写
int age;//可读可写,0-100岁合法
string lover;//只写
public:
//读年龄
int getage()
{
//age = 0;//初始化为0岁
return age;
}
void setage(int a)
{
if (a >= 0 && a <= 100)
{
age = a;
}
else
{
cout << "年龄非法" << endl;
age = 0;
}
}
};
int main()
{
person p;
p.setage(10);
cout << "年龄为:" << p.getage() << endl;
return 0;
}
练习案例一:设计立方体类:
设计立方体,属性为长宽高
求出面积和体积,使用全局函数和成员函数判断两个立方体是否相等。
#include<iostream>
using namespace std;
class Cube
{
private:
float m_L;
float m_H;
float m_W;
public:
//设置获取长宽高
void setlength(int length)
{
m_L = length;
}
void setwidth(int width)
{
m_W = width;
}
void sethight(int hight)
{
m_H = hight;
}
//获取
float getlength()
{
return m_L;
}
float getwidth()
{
return m_W;
}
float gethight()
{
return m_H;
}
//计算表面积
float calculateS()
{
return 2 * (m_L * m_H + m_L * m_W + m_W * m_H);
}
//计算体积
float calculateV()
{
return m_L * m_H * m_W;
}
//成员函数判断立方体是否相等
bool equal(Cube &c)
{
if (m_L == c.getlength() && m_W == c.getwidth() && m_H == c.gethight())
{
cout << "c1和c2是相等的" << endl;
return true;
}
else
{
cout << "c1和c2是不相等的" << endl;
return false;
}
}
};
//利用全局函数判断立方体是否相等
bool isSame(Cube c1, Cube c2)
{
if (c1.gethight() == c2.gethight() && c2.getlength() == c1.getlength() && c1.getwidth() == c2.getwidth())
{
cout << "c1和c2是相等的" << endl;
return true;
}
else
{
cout << "c1和c2是不相等的" << endl;
return false;
}
}
int main()
{
Cube c1;
c1.sethight(10);
c1.setlength(10);
c1.setwidth(10);
cout << "c1的面积为:" << c1.calculateS() << endl;
cout << "c1的体积为:" << c1.calculateV() << endl;
Cube c2;
c2.sethight(10);
c2.setlength(10);
c2.setwidth(10);
//全局函数判断相等
isSame(c1, c2);
//成员函数判断是否相等
c1.equal(c2);
return 0;
}
练习案例二:点与圆的关系
用 圆心坐标 x1和y1,点也有一个坐标x2,y2,圆有一个半径,点到圆心的距离与半径进行比较。
距离
为了简便,可以用距离平方和半径的平方
point.h
#pragma once
#include<iostream>
class Point
{
private:
int x;
int y;
public:
//设置
void setx(int a);
void sety(int a);
//获取
int getx();
int gety();
};
point.cpp
#include"point.h"
void Point:: setx(int a)
{
x = a;
}
void Point::sety(int a)
{
y = a;
}
//获取
int Point::getx()
{
return x;
}
int Point::gety()
{
return y;
}
circle.h
#pragma once
#include<iostream>
#include"point.h"
class Circle
{
private:
int m_R;//半径
//在类中,可以让另一个类作为本类的成员
Point m_Center;//圆心坐标
public:
//设置半径
void setr(int r);
//设置圆心
void setcenter(Point center);
//获取半径
int getr();
//获取圆心
Point getcenter();
};
circle.cpp
#include"circle.h"
//设置半径
void Circle::setr(int r)
{
m_R = r;
}
//设置圆心
void Circle::setcenter(Point center)
{
m_Center = center;
}
//获取半径
int Circle::getr()
{
return m_R;
}
//获取圆心
Point Circle::getcenter()
{
return m_Center;
}
main.cpp
#include<iostream>
#include"point.h"
#include"circle.h"
using namespace std;
void isInCircle(Circle& 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()
{
Circle c;
c.setr(10);
Point center;
center.setx(10);
center.sety(0);
c.setcenter(center);
Point p;
p.setx(10);
p.sety(10);
isInCircle(c, p);
return 0;
}