Linux 学习记录41(C++篇)
一、C++中的引用
在C语言中使用函数时,涉及到值传递与地址传递的问题
值传递:需要额外开辟空间,但是不能修改实参
地址传递:需要额外开辟空间,通过指针实现,能修改实参
1. 引用的定义
引用:是C++对C的一个重要的扩充
引用可以理解为给变量取别名,不会额外开辟空间
- 左值
一般是变量,栈区、堆区、.bss、.data
- 右值
一般是常量或者是临时值(4+5),.ro
定义格式:变量类型 &引用目标=要引用的变量;
例·:
using namespace std;
int main(int argc, char const *argv[])
{
int a = 99;
int &buf = a;
cout << a << endl;
cout << buf << endl;
cout << &a << endl;
cout << &buf << endl;
return 0;
}
输出:可以看到他们的值和地址都是一致的
2. 引用的注意事项
在C++中&有表示定义引用的作用,如果&前面是数据类型表示定义引用
1. 引用必须初始化
2. 指针可以指向NULL,但是引用不能指向NULL
3. 引用一旦指定就不能修改指向
4. 访问引用和访问变量取到的都是目标的值
3. 引用的基本使用
1. 一个目标可以有多个引用
2. 使用目标和使用引用是一样的值
3. 修改目标引用也会被修改,修改引用目标也会被修改
4. 引用和目标占用同一片空间
4. 引用作为函数的入口参数
例:
int add(int &a)
{
a*=a;
return a;
}
int main(int argc, char const *argv[])
{
int a = 10;
int &buf = a;
add(a);
cout << a << endl;
return 0;
}
输出结果:
5. 引用作为函数的返回值
引用作为返回值需要返回生命周期长的变量的引用
声明周期长的变量:
1. 全局变量
2. malloc申请的堆区空间
3. static修饰的局部变量
4. 实参传递过来的变量
int &add(int a,int b)
{
static int sum =a+b;
return sum;//返回了一个静态变量sum的引用
}
int main()
{
int a = 10;
int b = 20;
int buf = 25;
add(a,b) = buf;//这里将函数内sum的值修改为了buf的值
cout << a << endl;
return 0;
}
6. 常引用
常引用:不能通过引用修改目标,为了保护目标不被修改
通常用保护变量不被引用修改,只能使用变量名来修改
int main()
{
int a = 10;
const int &ret = a;
// ret = 90;//不能成立
a = 90;
cout << a << endl;
return 0;
}
7. 结构体引用
如果结构体中包含引用,在使用结构体定义变量是就必须对引用进行初始化
例:
typedef struct
{
int a;
char b;
int &ret;
}test_type;
int main()
{
int num = 90;
test_type buf = {1,2,num};//必须将结构体中的ret进行初始化
cout << buf.ret << endl;
return 0;
}
8. 指针和引用的区别
1. 引用必须初始化,指针不可以初始化
2. 指针可以指向NULL,引用必须有明确的目标
3. 指针能够改变指向,引用不能更改引用的目标
4. 指针需要额外开辟空间,引用不需要额外开辟空间,引用与目标使用同一片空间
5. 指针在使用前需要进行合理化检测,引用不需要。
6. 指针的大小由操作系统决定(64-8,32-4),而引用的大小和目标一致
7. 可以由多级指针,但是没有多级引用
8. 有指针数组,没有引用数组
二、C++中的动态内存分配
关键字:new,delete 用于C++中对于堆区空间申请和释放的关键字
1. new关键字
(1. 申请单个类型的空间
格式:指针 = new 数据类型
int main()
{
int* p = new int;//使用new关键字在堆区申请了一个int大小的空间
return 0;
}
(2. 申请单个类型的空间并赋值
格式:指针 = new 数据类型 (初始值)
int main()
{
int* p = new int (2);//使用new关键字在堆区申请了一个int大小的空间,并赋值
cout << *p << endl;
return 0;
}
(3. 申请单个类型的连续空间
格式:指针 = new 数据类型[空间大小]
int main()
{
int* arr = new int[5];//使用new关键字在堆区申请了一个int大小的空间,并赋值
return 0;
}
(4. 申请单个类型的连续空间并初始化
格式:指针 = new 数据类型[空间大小] {初始化的数据}
int main()
{
int* arr = new int[5] {0,1,2,3,4};//使用new关键字在堆区申请了一个int大小的空间,并赋值
for (int i=0;i<5;i++)
{
cout << *(arr+i);
}
return 0;
}
2. delete 关键字
在C++中指针置空常用nullptr,而不是NULL
(1. 释放单个空间
格式:delete 要释放的指针名;
int main()
{
int* p = new int;//使用new关键字在堆区申请了一个int大小的空间,并赋值
delete p;
p=nullptr;//给指针置空
return 0;
}
(2. 释放连续空间
格式:delete []空间首地址;
int main()
{
int* p = new int[5];//使用new关键字在堆区申请了一个int大小的空间,并赋值
delete []p;
p=nullptr;
return 0;
}
3. new/delete和C中malloc/free的区别
1. new返回的结果不需要强制转换,但是malloc需要强制转换
2. malloc申请空间时需要自己计算空间大小,new直接使用数据类型申请
3. new/delete是C++中的关键字,malloc/free是函数
4. new/delete在释放空间时需要考虑空间是否连续的问题,malloc/free在释放时不需要
5. new申请的空间可以初始化,malloc不能
6. new在申请空间时自动调用构造函数
7. delete在释放空间时会自动调用析构函数
三、C++中的函数
1. 函数重载(overload)
函数重载是实现静态多态的一种方式,能够实现"一名多用"
解决同一功能函数,不同参数类型,不能同名的问题
重载条件
1. 入口参数不同(可以是个数不同,可以是类型不同,可以是参数名不同等等)
2. 函数名相同
3. 作用域相同
4. 和返回值无关
例:
int add(int a,int b)
{
return a+b;
}
int add(int a,int b,int c)
{
return a+b+c;
}
double add(double a,double b)
{
return a+b;
}
string add(string a,string b)
{
return a+b;
}
int main()
{
cout << add(20,5) <<endl;
cout << add(20,5,7) <<endl;
cout << add(22.2,5.5) <<endl;
cout << add("20","5") <<endl;
return 0;
}
输出结果:
2. 函数的默认参数
函数重载和函数默认值尽量不要同时出现,可能会发送混乱
1. C语言中的函数参数都是由实参传递的,不能设置为默认参数
2. C++中可以使用,默认参数,给某些形参设置默认参数
3. 如果主调函数传递了实参,就使用实参,如果没有传递,就使用默认参数
4. 由于函数参数传递遵循靠左原则,设置默认参数必须从右到左开始设置(靠右原则)
5. 如果函数的某个参数设置了默认参数,则表示该参数右边的所有参数都有默认值
6. 主调函数写在了被调函数前,并且被调函数有默认参数,参数的默认值只能在函数声明的位置出现
double add(double a,double b=3.3);//函数声明
int add(int a,int b=5)//这里设置了默认参数
{
return a+b;
}
int main()
{
cout << add(22.2) <<endl;//第一个参数a使用了实参传值,b使用了默认参数
cout << add(20) <<endl;//第一个参数a使用了实参传值,b使用了默认参数
return 0;
}
double add(double a,double b)//这里设置了默认参数
{
return a+b;
}
输出:
3. 哑元
功能:指在函数的形参列表中没有实际意义的参数(只有类型),调用时也需要传递参数,但函数不会获取
使用场景:
1. 在一个大型的程序中,如果对某个已经hi用很久的功能,做了修改,但是又不想修改过多的代码,还要保证之前的代码也能使用,就可以把某些形参定义为哑元
2. :自增自减运算符的重载
int add(int a,int b,int)//这里第三个int就是哑元
{
return a+b;
}
4. 内联函数(inline)
函数是否被展开是编译器决定的,inline只是建议编译器
有些函数即使没有加inline也会被编译器展开
指在函数的调用前,将函数展开,在会在编译阶段将它展开
1. inline会建议编译器在(编译阶段)函数调用处展开函数
2. 一般要求内联函数的函数体足够小,一般在5行以内
3. 需要调用频繁
优点:效率高
缺点:会造成代码膨胀
定义格式:在函数定义前加上inline即可
例:
inline int add(int a,int b)//这里第三个int就是哑元
{
return a+b;
}
int main()
{
/*频繁调用*/
cout << add(10,20) << endl;
cout << add(10,20) << endl;
cout << add(10,20) << endl;
cout << add(10,20) << endl;
cout << add(10,20) << endl;
cout << add(10,20) << endl;
cout << add(10,20) << endl;
cout << add(10,20) << endl;
return 0;
}
四、C++中的结构体
1. C++中的结构体允许定义函数
2. C++中的结构体允许对成员进行初始化
3. C++中的定义结构体允许奴家struct
4. C++中的的结构体有访问权限
5. C++中的结构体可以被继承,C中不可以
6. C++中可以在结构体内封装另一个结构体,而C语言中只能在结构体中使用另一个结构体
结构体外无法访问结构体内的private(私有权限)的数据,只有结构体内部才能访问。结构体内的成员默认是public(公有权限)
例:
struct per
{
struct stu
{//结构体内的结构体定义,不占用pre结构体空间
int score;
};
int age=18;//对机构体内的变量进行初始化
char sex;
};
struct P
{
private: //私有的
int fat=90;
int high=180;
public: //公共的
void show(); //在结构体内实现函数的声明
};
//结构体外实现函数的定义
void P::show()
{//能够调用结构体内的私有权限的数据
cout << "fat=\t" << fat << endl;
cout << "high=\t" << high << endl;
}
int main()
{
cout << sizeof(per) << endl; //8,说明定义在per中的stu的声明,不占用内存空间
cout << sizeof(per::stu) << endl;
P p2;
//cout << "p2.high" << p2.high << endl; 私有的结构体成员,在结构体外不能访问
p2.show();
return 0;
}
五、class 类
C++中的类由C++中的结构体演变而来
结构体: 变量和函数
类: 成员属性(成员变量),成员方法(成员函数)
1. 定义
格式:类内的权限默认是private(私有权限)
class 类名
{
private:
//私有的成员属性/方法
public:
//公有的成员属性/方法
protected:
//受保护的成员属性/方法
}
权限
private类内可以访问,类外不能
public
类内可以访问,类外可以访问
protected
类内可以访问,类外不能
例:
class pre
{
private://私有的成员属性/方法
string name;
int age;
int high;
public://公有的成员属性/方法
void set(string str,int a,int h)
{
name=str;
age=a;
high=h;
}
void show(void)
{
cout << "name:" << name << endl;
cout << "age:" << age << endl;
cout << "high:" << high << endl;
}
protected://受保护的成员属性/方法
};
int main()
{
pre p;
p.set("a",18,180);
p.show();
return 0;
}
输出结果:
2. 封装
封装
- 将某一事物的所有属性(变量),行为(函数)都封装为一个整体,并对私有成员的私有成员属性,提供公有的接口,用户可以进行修改
- 类中每个成员都有属性限制(private,public,protected)
- 类中的访问权限是对于整个类而言的
- 类内,同一个访问权限,可以出现多次
- 类内默认是私有权限
3. 类和结构体的区别
- 继承:类支持继承,结构体不支持继承
- 初始化:类的实例可以通过构造函数来初始化,而结构体不能有无参构造函数
- 内存分配:类在实例化时会在堆上分配内存,而结构体则在栈上分配内存
- 默认权限:类的属性和方法默认的访问修饰符是 private,而结构体的属性和方法默认的访问修饰符是 public。
- 用法:一般来说,类被用于描述一组相关的对象,而结构体被用于描述一组相关的值
- 传递方式:当作为参数传递时,类是按照引用传递,而结构体是按照值传递
思维导图
文章来源:https://www.toymoban.com/news/detail-506361.html
练习
1. 定义一个矩形类(Rectangle) ,包含私有成员:长(length)、宽(width)
定义成员函数:
设置长度: void set l(intl)
设置宽度: void set_w(int w)
获取长度: int get_I();
获取宽度:int get_w();
展示函数输出该矩形的周长和面积: void show()文章来源地址https://www.toymoban.com/news/detail-506361.html
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cstdio>
using namespace std;
class Rectangle
{
private://私有的成员属性/方法
int length;//长
int width;//宽
public://公有的成员属性/方法
void set_l(int num)
{
length = num;
}
void set_w(int num)
{
width = num;
}
int get_l(void)
{
return length;
}
int get_w(void)
{
return width;
}
void show(void)
{
cout << "周长:" << (length+width)*2 << endl;
cout << "面积:" << length*width << endl;
}
protected://受保护的成员属性/方法
};
int main()
{
Rectangle rec;
int buf = 0;
cout << "请输入长:"<< endl;
cin >> buf;
rec.set_l(buf);
cout << "请输入宽:"<< endl;
cin >> buf;
rec.set_w(buf);
cout << "获取到的长:"<< rec.get_l() << endl;
cout << "获取到的宽:"<< rec.get_w() << endl;
rec.show();
return 0;
}
到了这里,关于Linux 学习记录41(C++篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!