友元:
采用类的机制后实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一般定义为公有的,依此提供类与外界间的通信接口。但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该函数的友元函数。除了友元函数外,还有友元类,两者统称为友元。友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。
友元函数:
友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:
friend 类型 函数名(形式参数);
友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
友元函数的调用与一般函数的调用方式和原理一致。
eg:
主函数:
// youyuan.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "UncleWang.h"
#include "Family.h"
void GetUncle_Heart(const UncleWang& uncle);
int _tmain(int argc, _TCHAR* argv[])
{
UncleWang uncle1;
uncle1.Hobby();
GetUncle_Heart(uncle1);
getchar();
return 0;
}
void GetUncle_Heart(const UncleWang& uncle)
{
cout << "要俘获的人的心的名:" << uncle.name << endl;
cout << "要俘获的人的心的龄:" << uncle.age << endl;
}
#include "UncleWang.h"
#pragma once
#define NAMELEN 10
class UncleWang
{
char* name;
int age;
public:
UncleWang();
void Hobby();
friend void GetUncle_Heart(const UncleWang& uncle);
~UncleWang();
};
UncleWang.cpp
#include "stdafx.h"
#include "UncleWang.h"
void UncleWang::Hobby()
{
cout << "我是隔壁" << this->name << ",我的年龄是:" << this->age << endl;
}
UncleWang::UncleWang()
{
this->name = new char[NAMELEN];
memset(this->name,0,NAMELEN);
strcpy(this->name,"老王");
this->age = 35;
}
UncleWang::~UncleWang()
{
delete[] name;
}
这就是友元函数。
友元类:
友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。
当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:
friend class 类名;
其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。
例如,以下语句说明类B是类A的友元类:
class A
{
…
public:
friend class B;
…
};
经过以上说明后,类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。
使用友元类时注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
A被B申明为友元类以后,在A的函数里,若B为参数,可直接访问B的成员与成员函数。
例:
main.cpp
// youyuan.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "UncleWang.h"
#include "Family.h"
void GetUncle_Heart(const UncleWang& uncle);
int _tmain(int argc, _TCHAR* argv[])
{
UncleWang uncle1;
//uncle1.Hobby();
//GetUncle_Heart(uncle1);
Family f;
uncle1.Uncle_visit_Family(f);
getchar();
return 0;
}
void GetUncle_Heart(const UncleWang& uncle)
{
cout << "要俘获的人的心的名:" << uncle.name << endl;
cout << "要俘获的人的心的龄:" << uncle.age << endl;
}
family.h
#pragma once
#define NAMELEN 10
class Family
{
char* mother;
char* father;
char* me;
public:
friend class UncleWang;
Family();
~Family();
void Show();
};
family.cpp
#include "stdafx.h"
#include "Family.h"
void Family::Show()
{
cout << "家庭成员:" << this->father<<" " << this->mother<<" " << this->me;
}
Family::Family()
{
this->father = new char[NAMELEN];
this->mother = new char[NAMELEN];
this->me = new char[NAMELEN];
strcpy(this->father,"父亲");
strcpy(this->mother, "母亲");
strcpy(this->me, "我");
}
Family::~Family()
{
delete[] father;
}
UncleWang.h
#pragma once
#define NAMELEN 10
#include "Family.h"
class UncleWang
{
char* name;
int age;
public:
UncleWang();
void Hobby();
friend void GetUncle_Heart(const UncleWang& uncle);
void Uncle_visit_Family(Family uncle);
~UncleWang();
};
UncleWang.cpp
#include "stdafx.h"
#include "UncleWang.h"
void UncleWang::Hobby()
{
cout << "我是隔壁" << this->name << ",我的年龄是:" << this->age << endl;
}
void UncleWang::Uncle_visit_Family(Family f)
{
cout << this->name << "拜访了" <<f.father << "一家"<<endl;
cout << "f的一家:";
f.Show();
}
UncleWang::UncleWang()
{
this->name = new char[NAMELEN];
memset(this->name,0,NAMELEN);
strcpy(this->name,"老王");
this->age = 35;
}
UncleWang::~UncleWang()
{
delete[] name;
}
运算符重载:
运算符重载的本质为函数重载,但有一定的规则需要遵循。
双目运算符尽量声明为友元,在类外写。cin cout 必须申明为友元。
第一点:
这里我们必须注意的是,重载的参数个数必须与运算符原意的个数一致。比如+号的参数就是左加数和右加数两个。那么当我们重载加号时也要保证有左右两个加数作为参数。
第二点:
重载作为普通函数时:
单目:右操作数是形参;双目:左边形参作为运算符左操作数,右边形参是右操作数。
重载作为类的成员函数时:
如果运算符参数只有一个,那么不需要写参数;如果运算符参数有两个,那么只需要写一个参数。
因为类的成员函数默认有一个this指针。它会直接指向类本身。换句话说,当我们写出运算符重载时,有一个参数就已经被this指针包含了。
单目运算符,this所指向运算符右参数,因为单目运算符的参数一般都在右边。
双目运算符,this指向运算符左参数。
以减号为例,两个时间类a和b相减时。如果是a - b,那么this指针指向a,反之则指向b。在声明函数时,我们只需要写右参数即可。a - b的话只需要写 int operator-(Time b);
当然,单目运算符由于只有一个参数,且该参数被this所指向,那么我们无需声明任何参数即可。
(二).返回值
运算符的返回值类型取决于该重载函数的作用是什么。
比如a + b的作用是得到一个加数,那么返回值就是a+b的值。a += b的作用是让a的值改变,既然是让参数a的值改变,那么就无需返回值。
还有就是如果我们需要运算符支持多次操作那么也需要返回值。比如流插入运算符<<。我们可能需要多次进行插入,像cout << a << b << c;之类就需要返回流ostream本身以便于之后的流插入工作。
<< >>运算符重载:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class String
{
private:
string str;
public:
String(string s){str=s;}
char & operator[](int i);
friend ostream & operator<<(ostream & cout, const String & st);
friend istream & operator>>(istream & cin, String & st);
};
char &String::operator[](int i)
{
return str[i];
}
ostream &operator<<(ostream & cout, const String &st)
{
cout << st.str;
return cout;
}
istream &operator>>(istream & cin, String &st)
{
char temp[40];
is.get(temp, 40);
if (cin)
st = temp;
while (cin && cin.get() != '\n')
continue;
return cin;
}
=运算符重载
#include <cstring>
#include <sstream>
class HugeInteger{
public:
HugeInteger& operator=(const HugeInteger &h);
private:
string str;
};
HugeInteger& HugeInteger::operator=(const HugeInteger &h)
{
this->str=h.str;
return *this;
}