目录
一、拷贝赋值函数
1.1 作用
1.2 格式
二、匿名对象
2.2 格式
三、友元
3.1作用
3.2格式
3.3 种类
3.4 全局函数做友元
3.5类做友元
3.6 成员函数做友元
3.7注意
四、常成员函数和常对象
4.1 常成员函数
4.1.1格式
示例:
4.2 常对象
作用:
格式:
示例:
4.3 mutable关键字
五、运算符重载
5.1概念
5.2 算术运算符的重载
1.成员函数实现:
5.3 关系运算符的重载
5.4 赋值运算符重载
5.5自增、自减运算符重载
自增为例:
1)前置自增
2)后置自增
5.6插入、提取运算符重载
5.7 不能重载的运算符
作业:实现关系运算符的重载
一、拷贝赋值函数
1.1 作用
用一个对象给另一个对象赋值。
1.2 格式
一、拷贝赋值函数
1.1 作用
用一个对象给另一个对象赋值。
1.2 格式
封装学生的类,写出构造函数,析构函数、拷贝构造函数、拷贝赋值函数
#include <iostream>using namespace std;//封装 学生 类
class Stu
{
private:string name;int age;
public://无参构造函数Stu() {cout << "无参构造函数" << endl;}//有参构造函数Stu(string name, int age):name(name),age(age){cout << "有参构造函数" << endl;}//拷贝构造函数Stu(const Stu& other):name(other.name){this->age = other.age;cout << "拷贝构造函数" << endl;}//拷贝赋值函数Stu & operator=(const Stu& other){if(this != &other) //避免自己给自己赋值{this->name = other.name;age = other.age;cout << "拷贝赋值函数" << endl;}return *this; //返回自己}~Stu(){cout << "析构函数" << endl;}void display(){cout << name << endl;}
};int main()
{Stu s1("zhangsan",12);s1.display();Stu s2 = s1; // s2.Stu(s1)s2.display();Stu s3;s3 = s1; //s3.operator=(s1)s3.display();return 0;
}
二、匿名对象
匿名对象就是没有名字的对象
用处:
1.用匿名对象给有名对象初始化
2.用匿名对象个对象数组初始化
3.用匿名对象做函数实参。
2.2 格式
类名()
#include <iostream>using namespace std;class Stu
{
private:string name;int age;
public://无参构造Stu() {}//有参构造Stu(string name,int age):name(name),age(age){}void show(){cout << name << endl;cout << age << endl;}
};
void fun(Stu s) //Stu s = Stu("lisi",23)
{s.show();
}int main()
{Stu s1 = Stu("zhangsan",34); //用匿名对象给有名对象初始化s1.show();Stu s[3] = {Stu("a",2),Stu("b",4),Stu("c",4)};fun(Stu("lisi",23)); //匿名对象做函数的实参return 0;
}
三、友元
3.1作用
友元,让一个函数或者类,访问另一个类的私有数据成员
3.2格式
friend xxxxxx
3.3 种类
- 全局函数做友元
- 类做友元
- 成员函数做友元
3.4 全局函数做友元
#include <iostream>using namespace std;//封装 房间 类
class Room
{friend void goodGay(Room &r);//goodGay函数是本类的好朋友,可以访问本类的所有成员private:string m_BedRoom; //卧室
public:string m_SittingRoom; //客厅
public://无参Room(){m_BedRoom = "卧室";m_SittingRoom = "客厅";}};//全局函数做友元
void goodGay(Room &r)
{cout << "好基友函数正在访问。。" << r.m_SittingRoom << endl;cout << "好基友函数正在访问。。" << r.m_BedRoom << endl;
}int main()
{Room r;goodGay(r);return 0;
}
3.5类做友元
#include <iostream>using namespace std;//封装 房间 类
class Room
{friend class GoodGay; //GoodGay这个类是本类的好朋友。可以访问本类的所有成员
private:string m_BedRoom; //卧室
public:string m_SittingRoom; //客厅
public://无参Room(){m_BedRoom = "卧室";m_SittingRoom = "客厅";}};//类做友元
class GoodGay
{
public:Room *r;void visit(){cout << "好基友类正在访问。。" << r->m_SittingRoom << endl;cout << "好基友类正在访问。。" << r->m_BedRoom << endl;}GoodGay(){r = new Room;}
};int main()
{GoodGay g;g.visit();return 0;
}
3.6 成员函数做友元
#include <iostream>using namespace std;class Room;//声明有这样的类//类做友元
class GoodGay
{
public:Room *r;void visit();//在类内声明GoodGay();};//封装 房间 类
class Room
{friend void GoodGay::visit(); //这个类的成员函数是本类的好朋友。可以访问本类所有成员
private:string m_BedRoom; //卧室
public:string m_SittingRoom; //客厅
public://无参Room(){m_BedRoom = "卧室";m_SittingRoom = "客厅";}};void GoodGay::visit() //在类外定义成员函数
{cout << "好基友类正在访问。。" << r->m_SittingRoom << endl;cout << "好基友类正在访问。。" << r->m_BedRoom << endl;
}
GoodGay::GoodGay()
{r = new Room;
}int main()
{GoodGay g;g.visit();return 0;
}
3.7注意
1.不要过度的使用友元,会降低封装性。
2.友元不具有交换性、传递性、继承性。
四、常成员函数和常对象
热知识:
const int a = 10; //a不能被改变
int const *p; //指针的指向可变,指向里的值不可变
int * const p; // 指针的指向不可变,指向里的值可变
int const * const p; //都不可变
const int fun(){} //返回值是不可以被改变的
4.1 常成员函数
所有非常成员函数,都可以对数据成员进行修改,如果想让一个成员函数不能对数据成员修改,那么就要用到常成员函数实现。
4.1.1格式
函数返回值类型 函数名(形参列表) const
{}
示例:
#include <iostream>using namespace std;
//封装 学生 类class Stu
{
private:string name;int age;public://无参构造函数Stu() {}//有参构造函数Stu(string n, int a):name(n),age(a){}void show() const{//age = 78; 常成员函数不能修改数据成员的值cout << "姓名:" << name << endl;cout << "年龄:" << age << endl;}
};
int main()
{Stu s("zhangsan",3);s.show();return 0;
}
4.2 常对象
作用:
常对象,表明这个对象的所有数据成员不能被改变。
常对象只能调用常成员函数,如果没有常成员函数,则报错。
非常对象对于常成员函数和非常成员函数都可以调用,优先非常成员函数。
常成员函数和非常成员函数构成重载,原因this指针类型不同。
格式:
const 类名 对象名;
示例:
#include <iostream>using namespace std;//封装 学生 类
class Stu
{
private:string name;int age;public://无参构造函数Stu() {}//有参构造函数Stu(string n, int a):name(n),age(a){}//常成员函数void show() const //Stu const * const this 都不可变{//age = 78; 常成员函数不能修改数据成员的值cout << "姓名:" << name << endl;cout << "年龄:" << age << endl;}//非常成员函数void show() // Stu * const this 指向不可变 指向的值可以变{age = 78;cout << "姓名:" << name << endl;cout << "年龄:" << age << endl;}
};int main()
{//非常对象Stu s("zhangsan",3);s.show();//常对象const Stu s1("lisi",4);s1.show();return 0;
}
4.3 mutable关键字
- mutable修饰变量 ---取消常属性
- mutable修饰数据成员,表示该数据可以在常成员函数中被修改
#include <iostream>using namespace std;
//封装 学生 类class Stu
{
private:string name;mutable int age; //在常成员函数中可以被修改
public://无参构造函数Stu() {}//有参构造函数Stu(string n, int a):name(n),age(a){}//常成员函数void show() const //Stu const * const this 都不可变{age = 78; //常成员函数不能修改数据成员的值cout << "姓名:" << name << endl;cout << "年龄:" << age << endl;}// //非常成员函数
// void show() // Stu * const this 指向不可变 指向的值可以变
// {
// age = 78;
// cout << "姓名:" << name << endl;
// cout << "年龄:" << age << endl;
// }
};int main()
{//非常对象Stu s("zhangsan",3);s.show();// //常对象
// const Stu s1("lisi",4);
// s1.show();return 0;
}
五、运算符重载
5.1概念
运算符重载 就是对运算符重新定义,赋予另一种功能,以适应不同的数据类型。
每个运算符重载都有两种实现方式:成员函数实现运算符重载、全局函数实现运算符重载
5.2 算术运算符的重载
- 种类:+ - * / %
- 表达式: L # R ( L:左操作数 #运算符 R: 右操作数)
- 左操作数:可以是左值,也可以是右值,在运算过程中 不会被改变
- 右操作数:可以是左值,也可以是右值,在运算过程中 不会被改变
- 结果:右值 (不可以被改变)
- 实现方式
1.成员函数实现:
const 类名 operator#(const 类名 &R) const{}// 1. cosnt 运算结果不能被改变2.cosnt 右操作数在运算过程中,不能被改变3.cosnt 左操作数在运算过程中,不能被改变2.全局函数实现:const 类名 operator#(const 类名 &L, const 类名 &R){}
#include <iostream>using namespace std;//封装人 类
class Person
{friend const Person operator+(const Person &L, const Person &R);
private:int a;int b;
public://无参构造函数Person() {}//有参构造函数Person(int a, int b):a(a),b(b){}//成员函数实现 + 号运算符重载
// const Person operator+(const Person &R) const
// {
// Person temp;
// temp.a = a + R.a;
// temp.b = b + R.b;// return temp;
// }void display(){cout << "a = " << a << endl;cout << "b = " << b << endl;}
};//全局函数实现+号运算符重载
const Person operator+(const Person &L, const Person &R)
{Person temp;temp.a = L.a + R.a;temp.b = L.b + R.b;return temp;}int main()
{Person p1(10,10);Person p2(10,10);//简化成://Person p3 = p1 + p2; //本质: p3 = p1.operator+(p2)Person p3 = p1 + p2; //本质: p3 = operator+(p1,p2)p3.display();//Person p4 = p1.operator+(p2);//p4.display();return 0;
}
5.3 关系运算符的重载
1> 种类:> >= <
2> 表达式: L # R ( L:左操作数 #运算符 R: 右操作数)
3> 左操作数:可以是左值,也可以是右值,在运算过程中 不会被改变
4> 右操作数:可以是左值,也可以是右值,在运算过程中 不会被改变
5> 结果:bool类型
6> 实现方式
1.成员函数实现:bool operator#(const 类名 &R) const{}
// 1. cosnt 运算结果不能被改变2.cosnt 右操作数在运算过程中,不能被改变3.cosnt 左操作数在运算过程中,不能被改变
2.全局函数实现:bool operator#(const 类名 &L, const 类名 &R){}
5.4 赋值运算符重载
1> 种类:= 、+=、-=、*=、/=、%=
2> 表达式: L # R ( L:左操作数 #运算符 R: 右操作数)
3> 左操作数:只能是左值
4> 右操作数:可以是左值,也可以是右值,在运算过程中 不会被改变
5> 结果:自身的引用
6> 实现方式
1.成员函数实现:类名 & operator#(const 类名 &R){}2.全局函数实现:类名 & operator#(类名 &L, const 类名 &R){}
5.5自增、自减运算符重载
自增为例:
1)前置自增
1.表达式 :++O
2.操作数:左值,运算过程中要被改变
3.结果:自身的引用
4.实现方式:成员函数实现: 类名 & operator++()全局函数实现: 类名 & operator++(类名 &O)
2)后置自增
1.表达式 :O++
2.操作数:左值,运算过程中要被改变
3.结果:右值 (不可以被改变)
4.实现方式:成员函数实现: const 类名 operator++(int)全局函数实现: const 类名 operator++(类名 &O,int)
#include <iostream>using namespace std;//封装人 类
class Person
{
// friend const Person operator+(const Person &L, const Person &R);friend Person & operator+=(Person &L, const Person &R);
private:int a;int b;
public://无参构造函数Person() {}//有参构造函数Person(int a, int b):a(a),b(b){}Person(const Person& p):a(p.a),b(p.b){}//成员函数实现 + 号运算符重载const Person operator+(const Person &R) const{Person temp;temp.a = a + R.a;temp.b = b + R.b;return temp;}//成员函数实现 >浩运算符重载bool operator>(const Person &R){if(a>R.a && b>R.b){return true;}else{return false;}}//成员函数实现+=运算符重载
// Person & operator+=(const Person &R)
// {
// a += R.a; // a = a + R.a;
// b += R.b;
// return *this;
// }//成员函数实现前++运算符重载Person & operator++(){++a;++b;return *this;}//成员函数实现后++运算符重载const Person operator++(int) //区别前置自增{Person temp;temp.a = a++;temp.b = b++;return temp;}void display(){cout << "a = " << a << endl;cout << "b = " << b << endl;}
};全局函数实现+号运算符重载
//const Person operator+(const Person &L, const Person &R)
//{
// Person temp;
// temp.a = L.a + R.a;
// temp.b = L.b + R.b;// return temp;
//}//全局函数实现+=运算符重载
Person & operator+=(Person &L, const Person &R)
{L.a += R.a;L.b += R.b;return L;
}int main()
{Person p1(10,10);Person p2(10,10);//简化成://Person p3 = p1 + p2; //本质: p3 = p1.operator+(p2)Person p3 = p1 + p2; //本质: p3 = operator+(p1,p2)p3.display();//Person p4 = p1.operator+(p2);//p4.display();if(p3>p1){cout << "p3>p1" << endl;}cout << "=======================" << endl;Person p4(3,4);p4 += p1;p4.display();cout << "=======================" << endl;p1 = ++p4;p1.display();p4.display();cout << "=======================" << endl;Person p5(7,8);p2 = p5++;p2.display();p5.display();return 0;
}
5.6插入、提取运算符重载
插入 >
cout 是 ostream 类的对象
cin 是 istream 类的对象
#include <iostream>using namespace std;//封装人 类
class Person
{
// friend const Person operator+(const Person &L, const Person &R);friend Person & operator+=(Person &L, const Person &R);friend ostream & operator<<(ostream &cout, const Person &p);friend istream & operator>>(istream &cin, Person &p);
private:int a;int b;
public://无参构造函数Person() {}//有参构造函数Person(int a, int b):a(a),b(b){}Person(const Person& p):a(p.a),b(p.b){}//成员函数实现 + 号运算符重载const Person operator+(const Person &R) const{Person temp;temp.a = a + R.a;temp.b = b + R.b;return temp;}//成员函数实现 >浩运算符重载bool operator>(const Person &R){if(a>R.a && b>R.b){return true;}else{return false;}}//成员函数实现+=运算符重载
// Person & operator+=(const Person &R)
// {
// a += R.a; // a = a + R.a;
// b += R.b;
// return *this;
// }//成员函数实现前++运算符重载Person & operator++(){++a;++b;return *this;}//成员函数实现后++运算符重载const Person operator++(int) //区别前置自增{Person temp;temp.a = a++;temp.b = b++;return temp;}void display(){cout << "a = " << a << endl;cout << "b = " << b << endl;}
};全局函数实现+号运算符重载
//const Person operator+(const Person &L, const Person &R)
//{
// Person temp;
// temp.a = L.a + R.a;
// temp.b = L.b + R.b;// return temp;
//}//全局函数实现+=运算符重载
Person & operator+=(Person &L, const Person &R)
{L.a += R.a;L.b += R.b;return L;
}//全局函数实现插入运算符重载
ostream & operator<<(ostream &cout, const Person &p)
{cout << p.a << endl;cout << p.b << endl;return cout;
}//全局函数实现提取运算符重载
istream & operator>>(istream &cin, Person &p)
{cin >> p.a;cin >> p.b;return cin;
}int main()
{Person p1(10,10);Person p2(10,10);//简化成://Person p3 = p1 + p2; //本质: p3 = p1.operator+(p2)Person p3 = p1 + p2; //本质: p3 = operator+(p1,p2)p3.display();//Person p4 = p1.operator+(p2);//p4.display();if(p3>p1){cout << "p3>p1" << endl;}cout << "=======================" << endl;Person p4(3,4);p4 += p1;p4.display();cout << "=======================" << endl;p1 = ++p4;p1.display();p4.display();cout << "=======================" << endl;Person p5(7,8);p2 = p5++;p2.display();p5.display();cout << "=======================" << endl;// operator<<(cout,p2)cout << p2 << endl; //本质 cout.perator<<(p2)//全局函数本质 operator<<(cout,p2)// ostream & operator<<(ostream &cout,const Person &p)cout << "=======================" << endl;Person p6;cin >> p6; //cin.operator>>(p2)// operator>>(cin,p6)// istream & operator>>(istream &cin, Person & p)cout << p6;return 0;
}
5.7 不能重载的运算符
- 成员运算符 .
- 成员指针运算符 ->
- 作用域限定符 ::
- 计算字节大小 sizeof()
- 三目运算符 ? :
作业:实现关系运算符的重载
#include <iostream>using namespace std;class Stu{int a;
public:Stu(){}Stu(int a): a(a){}//成员函数实现+号运算符重载bool operator > (const Stu &R) const{return a > R.a;}bool operator >= (const Stu &R) const{return a >= R.a;}bool operator < (const Stu &R) const{return a < R.a;}bool operator <= (const Stu &R) const{return a <= R.a;}bool operator == (const Stu &R) const{return a == R.a;}bool operator != (const Stu &R) const{return a != R.a;}};int main()
{Stu s1(10);Stu s2(100);cout << (s1>s2) << endl;cout << (s1>=s2) << endl;cout << (s1<=s2) << endl;cout << (s1<s2) << endl;cout << (s1==s2) << endl;cout << (s1!=s2) << endl;return 0;
}