一、友元
友元函数:友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
friend double FunctionName(参数列表 );
class CPoint
{
friend class CTest;
public:
CPoint(const double _dX = 0.0f, const double _dY =0.0f): m_dX( _dX), m_dY( _dY)
{}
friend double Distance( const CPoint _pt1, const CPoint _pt2);
//double Distance( const CPoint _pt1, const CPoint _pt2);
private:
double m_dX;
double m_dY;
};
1、友元函数说明:
a、友元函数可访问类的私有成员,但不是类的成员函数;
b、友元函数不能用const修饰;
c、友元函数可以在类定义的任何地方声明,不受类访问限定符限制;
d、一个函数可以是多个类的友元函数,但只需在各个类中分别声明;
e、友元函数的调用与普通函数的调用和原理相同;
f、其声明可以放在类的私有部分,也可以放在公有部分,无区别
2、友元类:友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员(当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一个类的友元类)。
友元的优缺点:提高了程序的运行效率;但破坏了类的隐藏性和封装性。
注意:友元关系是单向的,不能继承,不具有交换性,且不能传递。
二、赋值操作符的重载
重载操作符是具有特殊函数名的函数,关键字operator后面接需要定义的操作符符号。操作符重载也是一个函数,具有返回值和形参表。它的形参数目与操作符的操作数目相同,函数调用操作符可以接受任意数目的操作数。使用运算符重载可以提高代码的可读性。
返回类型 operate 操作符 (参数列表)
不可以被重载的操作符有:
成员选择符(.) 成员对象选择符(.*)
域解析操作符(::) 条件操作符(?:)
(除了赋值号=之外,基类中被重载的操作符都将被派生类继承)
注意:
1、不能通过连接其他符号来创建新的操作符:比如operator@;void operator @(){}
2、重载操作符必须有一个类类型或者枚举类型的操作数
int operator +(const int _iNum1 , const int _iNum2 )// 报错
{
return ( _iNum1 + _iNum2);
}
typedef enum TEST {one ,two ,three };
int operator+(const int _iNum1 , const TEST _test )
{
return _iNum1;
}
3、用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不能改变其含义
4、不再具备短求职特性重载操作符不能保证操作符的求值顺序,在重载&&和||中,对每个操作数都要进行求值,而且对操作数的求职顺序不能做规定,因此:重载&&、||和逗号操作符不是好的做法--重载后不能改变运算符的操作对象的个数以及其原有的优先级
5、作为类成员的重载函数,其形参看起来比操作数数目少1是因为成员函数的操作符有一个默认的形参this,限定为第一个形参。
CTest operator+(const CTest test1, const CTest test2)const // 报错
{
return test1;
}
CTest operator+(const CTest test1)const
{
return test1;
}
6、一般将算术操作符定义为非成员函数,将赋值运算符定义成员函数
7、操作符定义为非类的成员函数时,一般将其定义为类的友元
8、== 和 != 操作符一般要成对重载
9、下标操作符[]要重载两次:一个非const成员并返回引用,一个是const成员并返回引用
10、解引用操作符*和->操作符,不显示任何参数
11、自增自减操作符前置式++/--必须返回被增量或者减量的引用后缀式操作符必须返回旧值,并且应该是值返回而不是引用返回
12、输入操作符>>和输出操作符<<必须定义为类的友元函数(重载为类的成员函数不合理,调用时会与逻辑相反:a<<out;)
使用重载操作符,可以令程序更自然、更直观,而滥用操作符重载会使得类难以理解,在实践中很少发生明显的操作符重载滥用。但有些程序员会定义operator+来执行减法操作,当一个重载操作符不明确时,给操作符取一个名字更好,对于很少用的操作,使用命名函数通常比用操作符好,如果不是普通操作,没有必要为简洁而用操作符。
(编译器对于拷贝构造函数和赋值运算符在底层的实现相同)
例:实现一个复数类
//复数类
class Complex
{
public:
Complex(double real = 0.0,double image = 0.0)//构造函数
:_real(real)
,_image(image)
{}
Complex(const Complex& c)//拷贝构造函数
:_real(c._real)
,_image(c._image)
{}
Complex& operator=(const Complex c) //赋值运算符的重载
{
if(this != &c)
{
_real = c._real;
_image = c._image;
}
return *this;
}
Complex& operator*=(const Complex c) //*=符号的重载
{
_real *= c._real;
_image *= c._image;
return *this;
}
Complex& operator/=(const Complex c) // /=符号的重载
{
if(c._real != 0 && c._image != 0)
{
_real /= c._real;
_image /= c._image;
}
return *this;
}
Complex operator*(const Complex c) //乘号的重载
{
return Complex(_real*c._real,_image*c._image);
}
Complex operator/(const Complex c) //除号的重载
{
if(c._real != 0 && c._image != 0)
{
return Complex(_real/c._real,_image/c._image);
}
else
{
return *this;
}
}
Complex operator+(const Complex c) //加号的重载
{
return Complex(_real+c._real,_image+c._image);
}
Complex operator-(const Complex c) //减号的重载
{
return Complex(_real-c._real,_image-c._image);
}
Complex& operator+=(const Complex c) //+=重载
{
_real += c._real;
_image += c._image;
return *this;
}
Complex& operator-=(const Complex c) //-=重载
{
_real -= c._real;
_image -= c._image;
return *this;
}
bool operator == (const Complex& c) //==重载
{
return (_real==c._real && _image==c._image);
}
bool operator != (const Complex& c) //!=重载
{
return (_real!=c._real || _image!=c._image);
}
//复数不能比较大小
/*bool operator >=(const Complex& c)
{
return (_real>=c._real && _image>=c._image);
}
bool operator >(const Complex& c)
{
return (_real>c._real && _image>c._image);
}
bool operator <=(const Complex& c)
{
return (_real<=c._real && _image<=c._image);
}
bool operator <(const Complex& c)
{
return (_real<c._real && _image<c._image);
}*/
private:
double _real;
double _image;
};
int main()
{
Complex c1(1.0,2.0);
Complex c2(0.0,4.0);
Complex ret;
ret = c1 - c2;
ret = c1*c2;
ret = c1/c2;
system("pause");
return 0;
}
三、取地址操作符重载
四、const修饰的取地址操作符重载
关于const修饰类成员:
1、const修饰形参,一般和引用同时使用
2、const修饰返回值
3、const修饰类数据成员,必须在构造函数的初始化列表中初始化
4、const修饰类成员函数,实际修饰隐含的this,表示在类中不可以对类的任何成员进行修改
5、在const修饰的成员函数中要对类的某个数据成员进行修改,该数据成员定义声明是必须加mutable关键字
const对象不可以调用非const成员函数。
非const对象可以调用非const成员函数和const成员函数 。
const成员函数内可以调用其它的const成员函数。
非const成员函数内可以调用其它的const成员函数非const成员函数。
void FunTest()与void FunTest()const在类中构成函数重载,因为const修饰的是this指针,因此这两个函数的参数列表不同。