菜菜学C++之基础知识篇

一.知识点梳理

1. ubuntu下安装g++编译器

  • 在终端输入指令
sudo apt-get install build-essential

可以通过g++ -v查看是否安装成功

2. 重载

2.1 重载的概念

  • 出现在相同作用域中的函数,有相同的函数名,而形参表不同,称为重载函数
int max(int a, int b);
double max(double a , double b);
char* max(char* a, char* b);

2.2 函数重载与重复声明的区别

  • 两个函数的返回类型和形参完全匹配,则第二个函数声明称为第一个的重复声明,会报错

2.3 操作符重载

2.3.1 重载操作符的意义
  • 比如说一个类中有两个对象,如何实现两个对象的操作? ------ 对操作符进行重载,按照自己的意愿来操作两个对象或者对象
2.3.2 重载操作符的定义
  • 定义方法
    函数类型 operator 操作符名称 ( 形参表列 )
    {
    对操作符的重载处理
    }
  • 举个列子,要实现复数相加
Complex operator + ( Complex&  lc, Complex& rc)
{ 
	Complex c;
	c. real = lc.real + rc.real;
	c. img = lc.img + rc.img;
	return c; 
}
  • 可重载的操作符
    在这里插入图片描述
  • 不可以重载的操作符
..*::?sizeof
2.3.3 运算符重载的规则
  1. 重载操作符的函数的参数必须至少有一个是该类类型的对象
  2. 操作符重载不能改变操作符的结合性和优先级
  3. 重载操作符函数不能有默认的参数
  4. 有一些操作符在重载的时候需要谨慎对待

= & , && ||
如果不在类中定义赋值操作符重载,则编译器会自动的合成一个,按照类中定义的顺序,按每个成员的赋值操作符依次对每个成员进行赋值。
取地址操作符不需要重载就可以返回类对象的内存起始地址。
逗号操作符不需要重载就可以从左至右计算每个表达式的值,并返回最右边操作数的值。
逻辑与和逻辑或操作符有短路求值的特征,如果重载则失去短路求值的特征。

  1. 重载操作符的两种形式
    (1)类的成员函数

赋值(=)、下标([ ])、调用()、成员访问(->)必须定义为类的成员函数
复合的赋值操作符(+= -+ = /=)优先定义为成员函数,因为返回的是左操作数本身
改变对象的状态或与给定类型紧密联系的操作符,如自增、自减,解引用
等单目运算符,优先定义为成员函数

(2)类的友元函数

输入操作符>>, 输出操作符<<必须定义为类的友元函数
对称的操作符,如算术操作符,关系操作符,位操作符等双目运算符,优先定义成类的友元函数。
关系操作符重载函数必须返回true(非0)或false(0),即bool类型的值

2.4 算数运算符重载

  • 以加法为例子,优先定义算术操作符为友元函数。
Complex operator + (const Complex& c1,const Complex& c2)
{
	Complex sum;
	sum.real = c1.real + c2.real;
	sum.img = c1.img + c2.img;
	return sum;
}

对于既定义了算术操作符又定义了复合赋值操作符的类,优先使用复合赋值实现算术操作,可以不必创建和释放一个临时变量保存算术操作的结果。

2.5 关系运算符重载

  • 优先定义关系操作符为友元函数
  • 关系操作符重载函数必须返回true(非0)或false(0),即bool类型的值。
bool operator == (const Complex& c1,const Complex& c2)
{
	if(c1.real == c2.real && c1.img == c2.img)
		return true;
	else 
		return false;	
}

2.6 关系运算符重载

  1. 必须定义赋值操作符为成员函数,以便编译器知道是否需要合成一个默认的赋值操作符重载函数。
  2. 当类中有指针类型的数据成员或者有动态内存分配时,必须显式的定义赋值操作符。
  3. 为了满足连续赋值,赋值操作符返回当前类对象的引用。
Complex& Complex::operator = (const Complex& c1)
{
	if(this != &c1)
	{
		real = c1.real;
		img =  c1.img;
                  }
	return *this;		
}

2.7 输入输出操作符重载

  • 以输出操作符为例,输入与输出类似
  1. ostream是C++标准库的输出流类,cout是这个类的对象。表示输出到标准输出设备。
  2. 成员函数要求第一个操作数必须为该类对象,因此输出操作符必须定义为友元函数。
  3. 返回值类型为ostream类对象的引用,表示将输出流的现状返回,这样就可以进行连续的输出。
  4. 输出操作符里面所做的格式化应该尽量少,最好不要输出换行符。
ostream& operator  << ( ostream& out, const Complex & c)
{
	out<<(<<c.real<<,<<c.img<<);
	return out;
}

2.8 自增自减操作符重载

  1. 优先定义为成员函数。
  2. 注意前置运算和后置运算的区别。
  3. 前置运算应该返回被增量对象的引用。
  4. 后置运算应该返回未增之前的对象。
Complex& Complex::operator++()   //前置运算
Complex Complex::operator++(int)   //后置运算

2.8 调用操作符重载

  1. 为表示操作的类重载调用操作符。
  2. 调用操作符必须定义为类的成员函数。
  3. 调用操作符可以重载,由形参的数目或类型加以区别
  4. 定义了调用操作符的类,其类对象称为函数对象。
  5. 函数对象常用于标准库的算法。
    一般形式:
    <函数类型> 类名:: operator()(<形参表列>);
  6. 举个例题
//定义一个类Abs,这个类封装将int类型,double类型的对象转换为绝对值的操作。用调用操作符重载实现。 
#include <iostream>
using namespace std;
class Fbs
{
public:
	int operator()(int num){
		if (num >= 0){
			return num;
		}else{
			return -num;
		}
	}
	double operator()(double num){
		if (num >= 0){
			return num;
		}else{
			return -num;
		}
	}
};
int main(void){
	Fbs f;
	cout << f(-666) << endl;
	cout << f(666) << endl;
	cout << f(-666.666) << endl;
	return 0;
}

3. 引用

3.1 引用的概念

int a = 10;
int &b = a;

b称为a的引用,b是a的别名;引用变量b与变量a绑定在一起,也叫相关联。
&表示引用声明符,不是取地址符;b和a占同一内存存储单元。

  • 引用时的注意事项

1.定义一个引用时必须同时进行初始化
2.当引用初始化后,只要该引用存在,它就与初始化时指向的对象相关联,不能将引用关联到其它对象。
3.引用不是独立的数据类型,是复合类型,必须使其代表某一类型的对象。
4.可以定义数组引用

3.2 引用作为函数参数

  • 引用与非引用类型作为函数参数的区别?

形参具有非引用类型(不论是内置类型还是指针类型),形参复制实参的值。
形参为指针类型时,形参复制的是指针所指向对象的地址,所以函数内部可以通过对指针的使用,来修改指针所指向对象的值。
形参为引用类型时,它只是实参的别名,并不是实参的副本。
调用函数时,引用形参被创建,并且与相应的实参相关联,对形参的任何修改其实就是对实参的修改。
在C++中,建议多使用引用作为函数参数,比指针更方便

  • 使用引用形参的情况

需要在函数中改变实参的值
大型的对象(如类对象)作为实参传递时,此时复制对象所需要的时间和空间的代价都较大。

  • 以下一种情况必须使用引用形参:

对象无法进行复制时。(比如IO流对象)

3.3 引用作为函数返回值

  • 函数的返回值是用于初始化在函数调用处创建的临时对象
    在这里插入图片描述
  • 引用作为函数返回值需要注意的问题

函数返回引用类型时,不会复制返回值,返回的是对象本身。
不要返回绑定局部对象的引用,函数调用结束,局部对象被释放,返回的引用就会指向不确定的内存。
不要返回指向栈内存的指针,因为函数调用结束,局部对象被释放,返回的指针变成了指向不再存在对象的悬垂指针。

二.重难点

1.引用和指针的区别?

  • 从内存分配上来看:指针是一个实体,而引用仅是个别名。程序为指针变量分配内存区域,而引用不需要分配内存区域,它与它所绑定的对象占同一内存存储单元。
  • .“sizeof 引用”得到的是引用所绑定的对象的大小,而“sizeof 指针”得到的是指针本身的大小;
  • 引用使用时无需解引用(*),指针需要解引用;
  • 引用只能在定义时被初始化,之后就不能改变它和它所绑定的对象之间的联系,指针可改变指向。

2. 赋值操作符为什么必须被定义为成员函数?

定义为成员函数可以便于编译器知道是否需要合成一个默认的赋值操作符重载函数

3.输出操作符的返回值是什么类型?这样的目的是什么?

输出操作符的返回值类型是ostream的引用,是c++标准库的输出流类,这样的目的是表示将输出流的现状返回,这样就可以进行连续的输出。

4.输出操作符为什么必须被定义为友元函数?

因为成员函数要求第一个操作数必须为该类的对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值