在C++中,我们使用类对数据进行了隐藏和封装,类的数据成员一般都定义为私有成员,成员函数一般都定义为公有的,以此提供类与外界的通讯接口。但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该函数的友元函数。除了友元函数外,还有友元类,两者统称为友元。友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。
友元函数 :
友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:
friend 类型 函数名(形式参数);
友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
友元函数的调用与一般函数的调用方式和原理一致。
友元类 :
友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。
当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:
friend class 类名;
其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。
例子如下:
#include
using namespace std;
class A
{
public:
//
friend void modifyA(A *pA, int _a);
A(int a, int b)
{
this->a = a;
this->b = b;
}
int getA()
{
return a;
}
private:
int a, b;
};
void modifyA(A *pA,int _a)
{
pA->a = _a;
}
int main()
{
A a1(1, 2);
cout << a1.getA() << endl;
modifyA(&a1, 100);
cout << a1.getA() << endl;
system("pause");
return 1;
}
说明:声明一个友元函数,来修改类的私有属性。
输出:
1
100
请按任意键继续. . .
#include
using namespace std;
class A
{
public:
//
friend void modifyA(A *pA, int _a);
friend class B;
A(int a, int b)
{
this->a = a;
this->b = b;
}
int getA()
{
return a;
}
private:
int a, b;
};
class B
{
public:
void set()
{
objA.a = 10;
}
private:
A objA;
// int a, b;
};
void modifyA(A *pA,int _a)
{
pA->a = _a;
}
int main()
{
A a1(1, 2);
cout << a1.getA() << endl;
modifyA(&a1, 100);
cout << a1.getA() << endl;
system(“pause”);
return 1;
}
备注:在类a中声明, friend class B,然后再B中就可以访问类A的属性和方法了。
1.java—>1.class(字节码) == >class找到类的对象,直接修改类的私有属性。
所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之实现新功能,因此,一个函数名就可以用来代表不同功能的函数,也就是”一名多用”。
运算符也可以重载。实际上,我们已经在不知不觉之中使用了运算符重载。例如,大 家都已习惯于用加法运算符”+”对整数、单精度数和双精度数进行加法运算,如5+8, 5.8 +3.67等,其实计算机对整数、单精度数和双精度数的加法操作过程是很不相同的, 但由于C++已经对运算符”+”进行了重载,所以就能适用于int, float, doUble类型的运算。
又如”<<“是C++的位运算中的位移运算符(左移),但在输出操作中又是与流对 象cout 配合使用的流插入运算符,”>>“也是位移运算符(右移),但在输入操作中又是与流对象 cin 配合使用的流提取运算符。这就是运算符重载(operator overloading)。C++系统对”<<“和”>>“进行了重载,用户在不同的场合下使用它们时,作用是不同 的。对”<<“和”>>“的重载处理是放在头文件stream中的。因此,如果要在程序中用”<< “和”>>”作流插入运算符和流提取运算符,必须在本文件模块中包含头文件stream(当然还应当包括”using namespace std“)。
现在要讨论的问题是:用户能否根据自己的需要对C++已提供的运算符进行重载,赋予它们新的含义,使之一名多用。?
代码如下:
#include
using namespace std;
class Complex
{
public:
int a, b;
public:
Complex(int a = 0, int b = 0)
{
this->a = a;
this->b = b;
}
void printCom(){
cout << a << "+" << b <<"i"<< endl;
}
};
//第一步,定义全局函数。
Complex myAdd(Complex &c1, Complex &c2)
{
Complex tmp(1, 2);
return tmp;
}
//第二步,对函数名进行改造。
Complex operator+(Complex &c1, Complex &c2)
{
Complex tmp(c1.a+c2.a, c1.b+c2.b);
return tmp;
}
int main()
{
int a = 0, b = 0;
int c;
c = a + b;
Complex c1(1, 2) , c2(2, 3);
Complex c3; //用户自定义数据类型,C++默认情况下是不知道如何运算的。
// c3 = c1 + c2;
//C++编译器应该给我们程序员提供一种机制。。。
//让自定义数据类型有机会进行运算符操作,运算符重载体制。
/*Complex c4 = myAdd(c1, c2);
Complex c4 = operator+(c1, c2);*/
//第三步, 直接调用。
Complex c4 = c1 + c2;
c4.printCom();
system("pause");
return 1;
}
运算符重载的本质是 函数调用。
输出结果 3+5i;
#define _CRT_SECURE_NO_WARNINGS
#include
using namespace std;
//
class Name
{
public:
Name(const char *myp)
{
m_len = strlen(myp);
m_p =(char *) malloc(m_len + 1); //
strcpy(m_p, myp);
}
//Name obj2 = obj1;
//解决方案: 手工的编写拷贝构造函数 使用深copy
Name(const Name& obj1)
{
m_len = obj1.m_len;
m_p = (char *)malloc(m_len + 1);
strcpy(m_p, obj1.m_p);
}
//obj3 = obj1; // C++编译器提供的 等号操作 也属 浅拷贝
//obj3.operator=(obj1)
Name& operator=(Name &obj1)
{
//先释放旧的内存
if (this->m_p != NULL)
{
delete[] m_p;
m_len = 0;
}
//2 根据obj1分配内存大小
this->m_len = obj1.m_len;
this->m_p = new char [m_len+1];
//把obj1赋值
strcpy(m_p, obj1.m_p);
return *this;
}
~Name()
{
if (m_p != NULL)
{
free(m_p);
m_p = NULL;
m_len = 0;
}
}
protected:
private:
char *m_p ;
int m_len;
};
//对象析构的时候 出现coredump
void objplaymain()
{
Name obj1("abcdefg");
Name obj2 = obj1; //C++编译器提供的 默认的copy构造函数 浅拷贝
Name obj3("obj3");
obj3 = obj1; // C++编译器提供的 等号操作 也属 浅拷贝
//obj3.operator=(obj1)
//operato=(Name &obj1)
obj1 = obj2 = obj3;
//obj2.operator=(obj3);
//obj1 = void;
}
void main()
{
objplaymain();
cout<<"hello..."<
全局函数、类成员函数方法实现运算符重载步骤:
1)要承认操作符重载是一个函数,写出函数名称operator+ ()
2)根据操作数,写出函数参数
3)根据业务,完善函数返回值(看函数是返回引用 还是指针 元素),及实现函数业务
#include
using namespace std;
class Complex
{
public:
int a, b;
public:
Complex(int a = 0, int b = 0)
{
this->a = a;
this->b = b;
}
void printCom(){
cout << a << "+" << b <<"i"<< endl;
}
Complex operator-(Complex &c2)
{
Complex tmp(c2.a, c2.a);
return tmp;
}
};
//第一步,定义全局函数。
Complex myAdd(Complex &c1, Complex &c2)
{
Complex tmp(1, 2);
return tmp;
}
//第二步,对函数名进行改造。
Complex operator+(Complex &c1, Complex &c2)
{
Complex tmp(c1.a+c2.a, c1.b+c2.b);
return tmp;
}
int main()
{
//int a = 0, b = 0;
//int c;
//c = a + b;
Complex c1(1, 2) , c2(2, 3);
Complex c3; //用户自定义数据类型,C++默认情况下是不知道如何运算的。
//
c3= c1.operator-(c2);
c3.printCom();
//c4.printCom();
system("pause");
return 1;
}
输出 2+2i
#include
using namespace std;
class Complex
{
public:
int a, b;
friend Complex operator+(Complex &c1, Complex &c2);
public:
Complex(int a = 0, int b = 0)
{
this->a = a;
this->b = b;
}
void printCom(){
cout << a << "+" << b <<"i"<< endl;
}
Complex operator-(Complex &c2)
{
Complex tmp(this->a-c2.a,this->b- c2.b);
return tmp;
}
Complex &operator--()
{
this->a--;
this->b--;
return *this;
}
};
//第一步,定义全局函数。
Complex myAdd(Complex &c1, Complex &c2)
{
Complex tmp(1, 2);
return tmp;
}
//第二步,对函数名进行改造。
Complex operator+(Complex &c1, Complex &c2)
{
Complex tmp(c1.a+c2.a, c1.b+c2.b);
return tmp;
}
Complex& operator++(Complex &c1)
{
c1.a++;
c1.b++;
return c1;
}
int main()
{
//int a = 0, b = 0;
//int c;
//c = a + b;
Complex c1(11, 21) , c2(2, 3);
//Complex c3; //用户自定义数据类型,C++默认情况下是不知道如何运算的。
//c3= c1.operator-(c2);
//c3.printCom();
//++c1;
//c1.printCom();
//c4.printCom();
//成员函数方法实现--运算符。
c1.operator--();
c1.printCom();
system("pause");
return 1;
}