前言
本篇开始类的进阶内容,友元。
友元
类的访问控制权限要求,对于类的私有部分,只有类的公有方法才能访问。
友元是一个例外。
关键字friend
表示友元声明。
友元函数
友元函数不属于该类成员,但可以访问该类的私有成员。友元函数可以是普通函数,也可以是其它类的成员函数。
类的友元函数声明必须放在类中,示例如下:
#include <cstdio>
#include <iostream>
class SimpleClass{
private:
int a_;
public:
enum myEnum {ONE=1, TWO, THREE};
const int b = 10;
myEnum c;
SimpleClass(int a=1);
void set(int);
int get();
void add(int x) { // inline method
a_ += x;
}
friend int geta(const SimpleClass);
};
int geta(const SimpleClass c){
return c.a_;
}
SimpleClass::SimpleClass(int a){
a_ = a;
}
int main()
{
SimpleClass sc;
std::cout << geta(sc);
return 1;
}
SimpleClass
类的友元函数int geta(const SimpleClass)
可以访问类的私有成员a_
。
注意:友元函数必须在类中使用friend
关键字声明,但在定义时不能使用friend
关键字,除非在类内同时声明并定义。(在类声明中定义的友元函数也将成为内联函数)。
注意:友元函数可以声明在private
,public
,protected
中,位置无关紧要。
友元类
可以把类B声明为类A的友元类,这样类B中的所有成员函数都能访问类A中的私有成员。
类的友元类声明也必须放在类中,示例如下:
#include <cstdio>
#include <iostream>
class SimpleClass{
private:
int a_;
public:
enum myEnum {ONE=1, TWO, THREE};
const int b = 10;
myEnum c;
SimpleClass(int a=1);
void set(int);
int get();
void add(int x) { // inline method
a_ += x;
}
friend int geta(const SimpleClass);
friend class fClass;
};
class fClass{
public:
int geta(const SimpleClass);
};
int geta(const SimpleClass c){
return c.a_;
}
int fClass::geta(const SimpleClass c){
return c.a_;
}
SimpleClass::SimpleClass(int a){
a_ = a;
//b = a;
}
int main()
{
SimpleClass sc;
fClass fc;
std::cout << geta(sc) << std::endl;
std::cout << fc.getb(sc) << std::endl;
return 1;
}
SimpleClass
类的友元类fClass
中的成员函数fClass::geta()
也能够访问SimpleClass
的私有成员a_
。
注意:friend class fClass
同时声明了类fClass
的存在,以及fClass
是SimpleClass
的友元类,也就是说同时进行了类前置声明与友元声明。与下面的先前置声明类,后友元声明的方法等效:
class B;
Class A{
private:
// data member
public:
friend B;
}
class B{
private:
// data member
public:
// function member
};
友元成员函数
如果只需要类B的某个成员函数访问类A的私有成员,则可以将该成员函数声明为类A的友元成员函数。
注意:只有公有方法,才能成为友元成员函数。
友元成员函数的定义比较麻烦,需要特别关注类声明的顺序。示例如下:
class SimpleClass{
private:
int a_;
public:
enum myEnum {ONE=1, TWO, THREE};
const int b = 10;
myEnum c;
SimpleClass(int a=1);
void set(int);
int get();
void add(int x) { // inline method
a_ += x;
}
friend int geta(const SimpleClass);
friend class fClass;
friend int AClass::geta(const SimpleClass);
};
friend int AClass::geta(const SimpleClass)
声明类AClass中的geta()
是友元成员函数,因此需要在SimpleClass
声明之前,声明AClass
:
class AClass{
public:
int geta(const SimpleClass);
};
class SimpleClass{
private:
int a_;
public:
enum myEnum {ONE=1, TWO, THREE};
const int b = 10;
myEnum c;
SimpleClass(int a=1);
void set(int);
int get();
void add(int x) { // inline method
a_ += x;
}
friend int geta(const SimpleClass);
friend class fClass;
friend int AClass::geta(const SimpleClass);
};
AClass
声明中,int geta(const SimpleClass)
函数使用了SimpleClass
类,因此需要在AClass
声明之前,声明SimpleClass
:
class SimpleClass;
class AClass{
public:
int geta(const SimpleClass);
};
class SimpleClass{
private:
int a_;
public:
enum myEnum {ONE=1, TWO, THREE};
const int b = 10;
myEnum c;
SimpleClass(int a=1);
void set(int);
int get();
void add(int x) { // inline method
a_ += x;
}
friend int geta(const SimpleClass);
friend class fClass;
friend int AClass::geta(const SimpleClass);
};
class SimpleClass;
这样的声明称为前置声明,此时编译器知道了SimpleClass
是一个类,但不知道SimpleClass
类的内部成员。因此,要在SimpleClass
类声明后,再定义友元成员函数:
#include <cstdio>
#include <iostream>
class SimpleClass;
class AClass{
public:
int geta(const SimpleClass);
};
class SimpleClass{
private:
int a_;
public:
enum myEnum {ONE=1, TWO, THREE};
const int b = 10;
myEnum c;
SimpleClass(int a=1);
void set(int);
int get();
void add(int x) { // inline method
a_ += x;
}
friend int geta(const SimpleClass);
friend class fClass;
friend int AClass::geta(const SimpleClass);
};
class fClass{
public:
int geta(const SimpleClass);
};
int AClass::geta(const SimpleClass c){
return c.a_;
}
int geta(const SimpleClass c){
return c.a_;
}
int fClass::geta(const SimpleClass c){
return c.a_;
}
SimpleClass::SimpleClass(int a){
a_ = a;
}
int main()
{
SimpleClass sc;
fClass fc;
AClass ac;
std::cout << geta(sc) << std::endl;
std::cout << fc.geta(sc) << std::endl;
std::cout << ac.geta(sc) << std::endl;
return 1;
}
如果在SimpleClass
前置声明后,类声明前定义友元函数,就会报error: 'c' has incomplete type
,也就是SimpleClass
类型无法构造完整的对象。
注意:前置声明不能创建对象,不过可以创建对象的指针:
class AAA;
void main(){
AAA *aaa;
}
后记
本篇内容是类的进阶之,友元。下一篇将继续讲运算符重载。