1.友元函数与友元类
(1)友元函数:有一个类A,有一个函数叫func(),如果将func
()设为类A的友元函数,则func()可以访问类A中所有的成员,包括私有成员。
友元函数步骤:1.在类A的内部,先写上数func()的函数声明;
2.在函数声明前写上friend关键字。
友元函数说明:1.友元函数不是类的内部成员函数,是外部成员函数;
2.友元函数的声明不受访问控制符的限制。
friend Complex add(const Complex &a,const Complex
&b);
(2)友元类:如果类B是类A的友元类,则类B中所有成员函数都是A
的友元函数。
A向访问B的私有成员,就将A设为B的友元函数或者
友元类。
friend class Student;
(3)友元可以突破类的访问限制,访问类的私有成员---------破
坏了类的封装性,是一种很不友好的行为,正常情况下,不要轻易使用友元。
2.运算符的重载
(1)运算符重载:给运算符添加一种新的规则。
运算符重载步骤:1.写出函数名: operator + 要重载的运算符;
2.写出参数列表: 根据操作数的类型写出形参列表
;
3.返回值: 根据需要设置返回值。
Complex add(const Complex &a,const Complex &b);
===== Complex operator+(const Complex &a,const Complex
&b);
c = add(a,b);
===== c = operator+(a,b);//== c = a + b;
(2)c = c1 + 10;
编译器不知道一个Complex对象和一个int变量怎样计算?
-------> operator+(c1,10)
=======> Complex operator+(const Complex &,int )
(3)外部函数:通过友元的方式实现运算符重载(以上);
内部函数:
Complex operator+(const Complex &b(或者
&a))//后面加const,就与外部函数一样了
c = c1.operator+(c2);//Complex operator
+(Complex *const this,const Complex &c2);
运算符重载:内部和外部只能有一个。
(4)运算符重载的限制
3.自增自减运算符
A:前置 ++ --
++c1;
a:外部函数
Complex & operator++(Complex &c)//不能加const,因
为要自加
{
++c.a;
++c.b;
return c;
}
b:内部函数
Complex & operator++()
{
++a;
++b;
return *this;
}
B:后置 ++ --
后置++,有一个int型的占位参数进行区分。
c1++;
a:外部函数
Complex operator++(Complex &c,int)//不要&,因为
局部变量,不能返回引用
{
Complex tep(c.a,c.b);//加tep,主要是因为在
c = c1++ + c2时可以先运算,再自加
c.a++;
c.b++;
return tep;
}
b:内部函数
Complex operator++(int)
{
Complex tep(a,b);
a++;
b++;
return *this;
}
4,左移,右移运算符
(1)左移操作符
A: 外部函数
a:cout << c;
void(改为ostream &) operator<<(ostream &
out,const Complex &c)
{
out << c.a << "+" << c.b << "i";
或printf("%d + %di",a.c,c.b);
(加return out;)
}
b:cout << c << endl;//operator((operator<<
(cout,c)),endl)
cout << endl; //operator(cout,endl)
===>ostream & operator<<(ostream & out,ostream &
endl);
B:外部函数
ostream & operator<<(const Complex &c)去掉out
用this代替。需要将其放在ostream类中。
左移运算符无法进行内部重载(因为istream 类,头文
件等不能修改),只能进行外部重载,通过友元的方式
C:友元何时使用:无法操作左操作数的时候
不能用友元进行重载的操作符:= () [] ->
5.赋值运算符
(1)默认赋值运算符,做的是浅拷贝
Student s3;
S3 = s;
(2)自己重载赋值运算符
A:Student s3 = s;
operator=(s3,s);(= 不能用全局进行重载,只能进行
内部重载)
======> operator=(s);
======> Student & operator=(const Student &s)
{
if(this == &s)//1.判断是否是自己
{
return *this;
}
ifs.name== NULL)
{
delete [] name;
this->name = NULL;
id = s.id;
return *this;
delete [] name;//2.释放原有空间
thid->name = new char[20];//3.开辟新空间
this->id = s.id;//4.复制
strpy(this->name,s.name);
return *this;
}//2.3.是为了防止内存泄露
B:Student & operator=(const Student &s)
{
if(this != &s)//1.判断是否是自己
{
(//防止释放掉后,空间开辟未成功,在这可以
定义一个临时对象)
Student tep = s;//调用拷贝构造函数
//空间的交换
char *p = this->name;
this->name = tep.name;//新空间的地址
tep.name = p;
this->id = s.id;
}
return *this;
}
C:char *p = NULL;
free(p);
free(p);
指针指向NULL,可以重复释放,不会出现问题
6.其他运算符
(1)()函数调用运算符
Test t(10);
t();//()是运算符,函数调用运算符,函数对象,仿函数
(2) && ||
A: int a = 1;
int b = 0;
int c = 7;
b && (a = c);//b = 0 短路运算(不会执行)
a || (b = c);//a = 1 短路运算(不会执行)
B: A a1 = 1;
A b1 = 0;
A c1 = 7;
b1 && (a1 = c1)//&&运算符重载本质上是函数调用,所
以不具备逻辑运算符的短路功能
(3)数组下标运算符
#include <iostream>
using namespace std;
class Array
{
friend ostream& operator<<(ostream &out,Array &a);
public:
Array(int len)
{
if(len <= 0)
{
this->len = 0;
this->m_p = NULL;
}
this->len = len;
this->m_p = new int[this->len];
}
Array(const Array &a)
{
if(a.len == 0)
{
this->len = 0;
this->m_p = NULL;
}
else
{
this->len = len;
m_p = new int[this->len];
for(int i = 0;i < len;i++)
{
m_p[i] = a.m_p[i];
}
}
}
~Array()
{
if(m_p != NULL)
delete[] m_p;
m_p = NULL;
this->len = 0;
}
int getlen()
{
return len;
}
Array& operator=(const Array &a)
{
if(this != &a)
{
Array temp = a;
int *p = this->m_p;
this->m_p = temp.m_p;
temp.m_p = p;
this->len = a.len;
}
return *this;
}
int& operator[](int index)
{
return m_p[index];
}
private:
int len;
int *m_p;
};
ostream& operator<<(ostream &out, Array &a)
{
for(int i = 0;i < a.len;i++)
{
out << a[i] << " ";
}
return out;
}
int main()
{
Array a(10);
for(int i = 0;i < a.getlen();i++)
{
a[i] = i;
}
cout << a << endl;
return 0;
}
(1)友元函数:有一个类A,有一个函数叫func(),如果将func
()设为类A的友元函数,则func()可以访问类A中所有的成员,包括私有成员。
友元函数步骤:1.在类A的内部,先写上数func()的函数声明;
2.在函数声明前写上friend关键字。
友元函数说明:1.友元函数不是类的内部成员函数,是外部成员函数;
2.友元函数的声明不受访问控制符的限制。
friend Complex add(const Complex &a,const Complex
&b);
(2)友元类:如果类B是类A的友元类,则类B中所有成员函数都是A
的友元函数。
A向访问B的私有成员,就将A设为B的友元函数或者
友元类。
friend class Student;
(3)友元可以突破类的访问限制,访问类的私有成员---------破
坏了类的封装性,是一种很不友好的行为,正常情况下,不要轻易使用友元。
2.运算符的重载
(1)运算符重载:给运算符添加一种新的规则。
运算符重载步骤:1.写出函数名: operator + 要重载的运算符;
2.写出参数列表: 根据操作数的类型写出形参列表
;
3.返回值: 根据需要设置返回值。
Complex add(const Complex &a,const Complex &b);
===== Complex operator+(const Complex &a,const Complex
&b);
c = add(a,b);
===== c = operator+(a,b);//== c = a + b;
(2)c = c1 + 10;
编译器不知道一个Complex对象和一个int变量怎样计算?
-------> operator+(c1,10)
=======> Complex operator+(const Complex &,int )
(3)外部函数:通过友元的方式实现运算符重载(以上);
内部函数:
Complex operator+(const Complex &b(或者
&a))//后面加const,就与外部函数一样了
c = c1.operator+(c2);//Complex operator
+(Complex *const this,const Complex &c2);
运算符重载:内部和外部只能有一个。
(4)运算符重载的限制
3.自增自减运算符
A:前置 ++ --
++c1;
a:外部函数
Complex & operator++(Complex &c)//不能加const,因
为要自加
{
++c.a;
++c.b;
return c;
}
b:内部函数
Complex & operator++()
{
++a;
++b;
return *this;
}
B:后置 ++ --
后置++,有一个int型的占位参数进行区分。
c1++;
a:外部函数
Complex operator++(Complex &c,int)//不要&,因为
局部变量,不能返回引用
{
Complex tep(c.a,c.b);//加tep,主要是因为在
c = c1++ + c2时可以先运算,再自加
c.a++;
c.b++;
return tep;
}
b:内部函数
Complex operator++(int)
{
Complex tep(a,b);
a++;
b++;
return *this;
}
4,左移,右移运算符
(1)左移操作符
A: 外部函数
a:cout << c;
void(改为ostream &) operator<<(ostream &
out,const Complex &c)
{
out << c.a << "+" << c.b << "i";
或printf("%d + %di",a.c,c.b);
(加return out;)
}
b:cout << c << endl;//operator((operator<<
(cout,c)),endl)
cout << endl; //operator(cout,endl)
===>ostream & operator<<(ostream & out,ostream &
endl);
B:外部函数
ostream & operator<<(const Complex &c)去掉out
用this代替。需要将其放在ostream类中。
左移运算符无法进行内部重载(因为istream 类,头文
件等不能修改),只能进行外部重载,通过友元的方式
C:友元何时使用:无法操作左操作数的时候
不能用友元进行重载的操作符:= () [] ->
5.赋值运算符
(1)默认赋值运算符,做的是浅拷贝
Student s3;
S3 = s;
(2)自己重载赋值运算符
A:Student s3 = s;
operator=(s3,s);(= 不能用全局进行重载,只能进行
内部重载)
======> operator=(s);
======> Student & operator=(const Student &s)
{
if(this == &s)//1.判断是否是自己
{
return *this;
}
ifs.name== NULL)
{
delete [] name;
this->name = NULL;
id = s.id;
return *this;
delete [] name;//2.释放原有空间
thid->name = new char[20];//3.开辟新空间
this->id = s.id;//4.复制
strpy(this->name,s.name);
return *this;
}//2.3.是为了防止内存泄露
B:Student & operator=(const Student &s)
{
if(this != &s)//1.判断是否是自己
{
(//防止释放掉后,空间开辟未成功,在这可以
定义一个临时对象)
Student tep = s;//调用拷贝构造函数
//空间的交换
char *p = this->name;
this->name = tep.name;//新空间的地址
tep.name = p;
this->id = s.id;
}
return *this;
}
C:char *p = NULL;
free(p);
free(p);
指针指向NULL,可以重复释放,不会出现问题
6.其他运算符
(1)()函数调用运算符
Test t(10);
t();//()是运算符,函数调用运算符,函数对象,仿函数
(2) && ||
A: int a = 1;
int b = 0;
int c = 7;
b && (a = c);//b = 0 短路运算(不会执行)
a || (b = c);//a = 1 短路运算(不会执行)
B: A a1 = 1;
A b1 = 0;
A c1 = 7;
b1 && (a1 = c1)//&&运算符重载本质上是函数调用,所
以不具备逻辑运算符的短路功能
(3)数组下标运算符
#include <iostream>
using namespace std;
class Array
{
friend ostream& operator<<(ostream &out,Array &a);
public:
Array(int len)
{
if(len <= 0)
{
this->len = 0;
this->m_p = NULL;
}
this->len = len;
this->m_p = new int[this->len];
}
Array(const Array &a)
{
if(a.len == 0)
{
this->len = 0;
this->m_p = NULL;
}
else
{
this->len = len;
m_p = new int[this->len];
for(int i = 0;i < len;i++)
{
m_p[i] = a.m_p[i];
}
}
}
~Array()
{
if(m_p != NULL)
delete[] m_p;
m_p = NULL;
this->len = 0;
}
int getlen()
{
return len;
}
Array& operator=(const Array &a)
{
if(this != &a)
{
Array temp = a;
int *p = this->m_p;
this->m_p = temp.m_p;
temp.m_p = p;
this->len = a.len;
}
return *this;
}
int& operator[](int index)
{
return m_p[index];
}
private:
int len;
int *m_p;
};
ostream& operator<<(ostream &out, Array &a)
{
for(int i = 0;i < a.len;i++)
{
out << a[i] << " ";
}
return out;
}
int main()
{
Array a(10);
for(int i = 0;i < a.getlen();i++)
{
a[i] = i;
}
cout << a << endl;
return 0;
}