C++面向对象整理(4)之friend关键字(类的友元)
注:整理一些突然学到的C++知识,随时mark一下
例如:忘记的关键字用法,新关键字,新数据结构
C++ 的 类的友元
提示:本文为 C++ 中 类定义、成员函数 的写法和举例
一、类的友元
1、友元的定义
在C++中,友元(friend)是除了public、private、protected
外的一种特殊的访问权限控制的机制,它允许一个类或函数访问当前类的私有(private)和保护(protected)成员。语法格式是在类的定义内添加一句关键字friend
开头的声明。
但这种机制打破了封装性,因此在使用时应谨慎。然而,在某些情况下,如运算符重载或需要访问另一个类的内部状态的函数中,友元可能是有用的。
2、类作为友元
当一个类A
声明另一个类B
为其友元时,这个友元类B
可以访问其A
的所有成员,包括私有和保护成员。
class ClassA {
private:
int secret;
public:
ClassA(int s) : secret(s) {} //初始化列表
friend class ClassB; // 声明ClassB为友元类
};
class ClassB {
public:
void revealSecret(ClassA& a) {
std::cout << "The secret of ClassA is: " << a.secret << std::endl; // 可以访问ClassA的私有成员
}
};
3、函数作为友元
一个非成员函数,也就是全局的函数也可以被声明为某个类的友元,这样它就可以访问该类的私有和保护成员。
class ClassA {
private:
int secret;
public:
ClassA(int s) : secret(s) {}
friend void printSecret(ClassA& a); // 声明printSecret为友元函数
};
void printSecret(ClassA& a) {
std::cout << "The secret of ClassA is: " << a.secret << std::endl; // 可以访问ClassA的私有成员
}
4、成员函数作友元
成员函数也可以作为另一个类的友元。这意味着这个成员函数能够访问另一个类的私有(private)和保护(protected)成员。这种机制在某些特定的编程场景中可能非常有用,尤其是在需要跨类访问或修改数据成员时。
下面展示了如何将一个类的成员函数声明为另一个类的友元:
class ClassB {
private:
int privateMember;
public:
ClassB(int value) : privateMember(value) {}
// ClassA的成员函数作为ClassB的友元
friend void ClassA::showPrivateMemberOfB(ClassB& objB);
};
class ClassA {
public:
// ClassA的成员函数,它可以访问ClassB的私有成员
void showPrivateMemberOfB(ClassB& objB) {
std::cout << "Private member of ClassB: " << objB.privateMember << std::endl;
}
};
int main() {
ClassB objB(42);
ClassA objA;
objA.showPrivateMemberOfB(objB); // 输出ClassB的私有成员
return 0;
}
在这个例子中,ClassA
的showPrivateMemberOfB
成员函数被声明为ClassB
的友元。因此,尽管privateMember
是ClassB
的私有成员,showPrivateMemberOfB
函数仍然能够访问它。
5、友元应当限制使用
使用成员函数作为友元时,需要特别注意以下几点:
封装性破坏:与任何其他友元关系一样,成员函数作为友元也会破坏封装性。这意味着类的内部状态可能会被不当地访问或修改,从而影响类的完整性和安全性。
谨慎使用:由于友元关系破坏了封装性,因此应该尽量避免使用它,特别是在大型项目中。如果可能的话,最好通过公共接口(如公有成员函数)来访问和修改类的状态。
考虑替代方案:在决定使用成员函数作为友元之前,应该仔细考虑是否有其他更安全的替代方案,例如提供特定的访问函数或使用更高级的设计模式。
清晰注释:如果确实需要使用成员函数作为友元,那么在代码中应该添加清晰的注释,解释为什么需要这样做以及可能带来的风险和后果。这有助于其他开发者理解你的设计决策并维护代码的可读性和可维护性。
7、拷贝构造函数必须用const引用传递
(关于拷贝构造函数)拷贝构造函数的形参不能使用值传递或指针传递,原因如下:
(1)如果拷贝构造函数的形参使用值传递,那么在调用拷贝构造函数时,需要将实参传递给形参。这个传递过程本身就需要调用拷贝构造函数来完成。这会导致一个无限递归的情况,因为每次调用拷贝构造函数都会再次触发拷贝构造函数的调用,最终造成栈溢出。编译器在语法检查阶段就会禁止这种行为。
(2)如果拷贝构造函数的形参使用指针传递,那么这样的构造函数实际上就不再被视为拷贝构造函数,而是一个自定义的有参构造函数。拷贝构造函数具有特定的定义和用途,即用于创建一个新对象作为现有对象的副本,指针传递只是拷贝了指针。