C++第二周学习笔记(接上篇)

作者也是新手,笔记中或许有不足,如果有疑问可以在评论区指出更正,希望谅解。

1.1成员函数做友元

一个类的成员函数访问另一个类的属性。当需要访问私有属性时,需要在另一个类中进行说明,访问其他属性时可以不声明。 

class Friend
{
  public:
     void visit(){}
}
class Buliding
{
  friend void visit();//声明Friend的成员函数visit是这个类的友元函数,可以访问私有属性

  private:
     string m_Bedroom="卧室";
}

 1.2重载运算符:有的类的属性可能是通过几个类的属性运算获得,但是编译器并不知道该如何运算,因此使用运算符重载告知编译器如何运算得到结果。

 1.2.1加号重载

(1)成员函数重载

class Person
{
  public:
	//Person p3=p1.operator+(p2);
	Person operator+(Person& p)//成员函数重载+号
	{
		Person temp;
		temp.A = this->A + p.A;
		temp.B = this->B + p.B;
		return temp;
	}
	int A;
	int B;	
}
void test1()
{
	Person p1;
	p1.A = 10;
	p1.B = 10;
	Person p2;
	p2.A = 10;
	p2.B = 10;
	Person p3=p1+p2;	//Person p3=p1.operator+(p2);
	cout << "p3.A=" << p3.A << endl;
	cout << "p3.B=" << p3.B << endl;
}
int main() 
{
	test1();
	return 0;
}

(2)全局函数重载

class Person
{
public:
	int A;
	int B;	
}
//Person p3=operator+(p1,p2);
Person operator+(Person& p1, Person& p2)//全局函数重载+号
{
	Person temp;
	temp.A = p1.A + p2.A;
	temp.B = p1.B + p2.B;
	return temp;
}
void test1()
{
	Person p1;
	p1.A = 10;
	p1.B = 10;
	Person p2;
	p2.A = 10;
	p2.B = 10;
	Person p3=p1+p2;//Person p3=operator+(p1,p2);
	cout << "p3.A=" << p3.A << endl;
	cout << "p3.B=" << p3.B << endl;
}
int main()
{
   test1();
   return 0;
}

1.2.2左移号重载

只能用全局函数,因为成员函数重载p.operator<<(cout)简化版本为p<<cout,而我们要的是cout<<p。

class Person
{
  public:
   int m_A;
   int m_B;
}
ostream &operator(ostream &cout,Person &p)//全局函数,本质:cout<<p,ostream是输出流类型
{
   cout<<p.m_A<<endl<<p.m_B;//这个函数的类型是输出流,相比于void,它可以做输出链
}

1.2.3递增号重载

//重载前置++运算符(++i)
	MyInteger &operator++()
	{
		++m_Num;
		return *this;		//将类本身做返回
	}

//重载后置++运算符(i++)
	MyInteger operator++(int)	//int 代表占位参数,用于区分前置和后置递增
	{
		MyInteger temp = *this;
		m_Num++;
		return temp;		//将类本身做返回,局部变量temp会被释放,因此返回值而不是引用&
	}

(1).重载前置运算符不需要传入参数,而重载后置运算符需要传入一个占位参数int

(2).重载前置运算符返回的是引用,后续可以对该值继续链式调用; 重载后置运算符直接返回局部变量的,因为局部变量在函数调用完后就被释放,所以如果引用一个局部变量地址就会报错。

1.2.4赋值符号重载

编译器默认的赋值运算符为浅拷贝(拷贝对象和原对象指向同一片存储空间,可能引发释放问题),因此在拷贝类的属性时需要将赋值运算符重载,进行深拷贝(拷贝对象和原对象指向不同存储空间),以解决堆区重复释放问题。

Person &operator=(Person& p)
	{
		//先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝
		if (m_Age)
		{
			delete m_Age;//释放堆区
			m_Age = NULL;
		}
		//深拷贝
		m_Age = new int(* p.m_Age);//设置新堆区
		return *this;//返回本身
	}

1.2.5关系运算符重载

编译器并不知道如何比较自定义数据类型的关系,因此需要重载关系运算符告知编译器如何比较

关系运算符一共有6种:==、!=、<、>、<=、>=

这里主要就 == 和 != 进行讲解,其他类似

值得注意的是,关系运算符要成对重载,比如== 和 != 都要重载

class Person
{
   public:
     Person(string name,int age)
     {
        m_Name=name;
        m_Age=age;
     }
     string m_Name;
     int m_Age;
    
    bool operator==(Person &p)//判断是否要使用布尔类型
   { 
      if(this->m_Name==p.m_Name && his->m_Age==p.m_Age)
         return true;
      else
         return false;//布尔类型返回是和否
   }
     bool operator!=(Person &p)//重载了==就要重载!=,成对重载
   { 
      if(this->m_Name==p.m_Name && his->m_Age==p.m_Age)
         return false;//因为!=是不相等的意思,所以如果属性相等,那么应该判断否
      else
         return true;//不等则判断是
   }
}

1.2.6函数调用运算符重载

函数调用运算符是()

class Add
{
   public:
    int operator()(int p1,int p2)//两个整型相加结果还是整型
    { 
       return p1+p2;  
    }
}
void test1
{
  Add add;
  cout<<add(10,10)<<endl;
  cout<<Add()(10,10)<<endl;//Add()是匿名对象,起到跟add一样的作用
}

因为函数调用运算符重载很像函数,所以也被叫做仿函数,仿函数的作用十分灵活。

还在学习中.......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值