作业:
1.定义一个矩形类(Rectangle),包含私有成员:长(length)、宽(width),
定义成员函数:
设置长度:void set_l(int l)
设置宽度:void set_w(int w)
获取长度:int get_l();
获取宽度:int get_w();
展示函数输出该矩形的周长和面积:void show()
#include <iostream>
using namespace std;
class rect{
private:
int length;
int width;
public:
void set_i(int i);//设置长度
void set_w(int w);
int get_i();
int get_w();
void show();
};
void rect::set_i(int i){
length=i;
}
int rect::get_i(){
int i;
cout<<"请输入长度"<<endl;
cin>>length;
set_i(length);
}
void rect::set_w(int w){
width=w;
}
int rect::get_w(){
cout<<"请输入宽度"<<endl;
cin>>width;
return width;
set_w(width);
}
void rect::show(){
int d=(length+width)*2;
int s=(length*width);
cout<<"周长为"<<d<<endl;
cout<<"面积为"<<s<<endl;
}
int main()
{
rect r1;
r1.get_i();
r1.get_w();
r1.show();
return 0;
}
一、左值引用
1.概念
左值:可以被赋值,既能作为左值也能作为右值的量
右值:只能作为右值,一般都是临时值
引用相当于给变量起了一个别名,使用引用和变量名都是访问该变量
引用不会额外开辟空间
2.定义&
数据类型 &引用名 = 目标;
引用必须初始化
&的用法:
- 取变量的内存地址
- 按位与
- &&逻辑与
- &表示定义引用
如何区分何时是定义引用何时是取地址?
如果&前面有数据类型,说明是定义引用
如果&前面没有数据类型,说明是取变量地址
3.引用的基本类型
- 引用必须初始化(引用必须有目标)
- 引用一旦指定目标,不能发生修改
- 引用和变量公用同一片空间,访问到的是相同的值,一个发生修改另一个也跟着修改
- 一个目标可以有多个引用,但是一个引用不能有多个目标
4.引用作为函数的形参
- 可以直接在函数内部修改实参的值
- 不需要额外开辟空间
例:引用作为函数的参数,实现冒泡排序
#include <iostream>
using namespace std;
//冒泡排序的函数,形参是数组的引用
void sort(int (&arr)[6])
{
int len = sizeof (arr)/sizeof (arr[0]),temp;
for(int i=1;i<len;i++)
{
for(int j=0;j<len-i;j++)
{
if(arr[j]>arr[j+1])
{
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
int main()
{
int a =90;
int &rea = a; //定义a的引用
int arr[6]={12,90,87,45,32,67};
//给arr数组定义一个引用
int (&ref)[6] = arr; //引用的数据类型和目标的数据类型一致
//(&ref)表示ref是一个引用
sort(arr);
int *p = &a;
//写一个指针p的引用
int *&rep = p;
//定义二级指针的引用
int **q = &p;
int **&re2 = q;
return 0;
}
5.引用作为函数的返回值
引用作为函数的返回值,需要返回声明周期长的变量的引用:
- 全局变量
- 静态局部变量
- 堆区申请的空间
- 实参传递过去的空间
#include <iostream>
using namespace std;
//int x = 90;
int &fun(int &x)
{
//static int x = 90;
int &re1 = x; //定义了变量x的引用re1
return re1;
}
int main()
{
int a = 100;
//即然引用是左值,如果函数的返回值是引用,可以被赋值
fun(a) = 90; //--->相当于给返回的变量赋值
cout << fun(a) << endl; //由于返回的是a的引用,所以上面一条语句相当于对a变量值的修改
cout << a << endl;
return 0;
}
6.引用和指针的区别
- 指针不需要初始化,引用必须初始化
- 指针的指向可以修改,引用的目标一旦指定不能修改
- 指针可以指向NULL,引用不能引用NULL
- 指针在使用前需要做合理性检查,引用不需要做合理性检查
- 指针的大小是固定的8/4Byte,引用的大小和目标保持一致
- 指针是开辟了新的空间,引用没有开辟新的空间
- 有指针数组,但是没有引用数组
- 有多级指针,没有多级引用
二、C++中的动态内存分配
1.new
申请单个空间
数据类型 *指针名 = new 数据类型; //从堆区申请一个数据类型的空间
数据类型 *指针名 = new 数据类型(初始值);
申请连续空间
数据类型 *指针名 = new 数据类型[个数]; //申请空间但是不初始化
数据类型 *指针名 = new 数据类型[个数]{初始值···}; //申请空间并初始化,可以完全初始化也可以不完全初始化
2.delete
释放单个空间:
delete 指针名;
释放连续空间: delete []指针名; //[]中无需添加空间个数,自动释放
C++中指针置空尽量使用nullptr
3.malloc/free和new/delete的区别
- new/delete是C++中的关键字,malloc/free是C语言中的函数
- malloc的返回值需要强转,new的结果无需强转
- malloc申请的空间不能初始化,new申请的空间可以初始化
- malloc申请空间时以字节为单位申请,new申请空间以数据类型为单位
- malloc申请单个空间和申请连续空间格式没有区别,new申请连续空间和申请单个空间的格式不同
- delete释放空间时需要考虑是否是连续空间,free不需要考虑连续空间的问题
- new在申请空间时会自动调用构造函数
- delete在释放空间时会自动调用析构函数
三、C++中的函数
1.要求
与返回值没有关系
- 函数名相同
- 参数不同(类型/个数)
- 作用域相同
重载
int add(int a,int b) //addii
{
return a+b;
}
double add(double a,double b) //adddd
{
return a+b;
}
string add(string s1,string s2) //addss
{
return s1+s2;
}
2.函数参数的默认值
- C语言中形参都是由实参进行初始化的,C++中函数的参数支持默认值
- 由于函数传参都是靠左原则,所以函数参数的默认值靠右原则,如果一个参数有默认值,说明该参数右侧的所有参数都已经有默认值了
- 如果有默认值的参数没有实参传过来的值,就使用默认值,如果既有默认值也有实参传的值,使用实参传递过来的值
- 如果参数有默认值的函数,参数的默认值只能出现在声明的位置
- 函数参数的默认值尽量不要和函数重载同时出现,会造成调用混乱的问题
四、C++中的结构体
- C++中结构体中的成员变量允许有初始值
- C++中的结构体可以定义函数
- C++中结构体成员变量可以有访问权限:private(私有)、public(公有)、protected(受保护的)
- C++中结构体可以被继承
- C++中可以在结构体中封装另一个结构体类型
- C++中的结构体可以省略struct直接使用结构体名定义变量
结构体中的函数,可以只在结构体中声明,在结构体外定义
结构体中的私有成员,可以使用结构体中的公有方法,在结构体外被访问
结构体中成员的默认访问权限是公有权限
#include <iostream>
using namespace std;
struct Stu
{
public:
string name = "zhangsan"; //给成员变量初始值
void show();
//在结构体中只书写函数声明
int add(int a,int b);
//给私有的成员,设置一个公有的方法,来给成员变量赋值
void set_age(int a);
private:
int age; //给成员变量age设置为私有权限
};
//在结构体外实现函数
int Stu::add(int a,int b)
{
return a+b;
}
void Stu::set_age(int a)
{
age = a; //给私有成员赋值
}
void Stu::show() //在结构体中定义函数
{
cout << name << endl;
cout << age << endl;
}
int main()
{
//省略struct直接定义结构体变量
Stu s1;
//s1.age = 90; 私有成员,不能在结构体外访问
s1.set_age(20); //通过公有的方法给私有的成员赋值
s1.show();
return 0;
}