使用 friend 关键字和使用成员函数修改类内部的私有变量有什么区别
What is the difference between using the friend keyword, and using a member function to modify private variables inside of a class?
正如问题所问...
两者之间有什么区别:
class MyClass
{
public:
MyClass(){
m_a = 0;
}
private:
int m_a;
friend void set_a(MyClass &a);
};
void set_a(MyClass &a)
{
std::cout << a.m_a << std::endl;
a.m_a = 500;
std::cout << a.m_a << std::endl;
}
int main(void) {
MyClass my_class_instance;
set_a(my_class_instance);
system("pause");
}
和:
class MyClass
{
public:
MyClass(){
m_a = 0;
}
void set_a(){
std::cout << this->m_a << std::endl;
this->m_a = 500;
std::cout << this->m_a << std::endl;
}
private:
int m_a;
};
int main(void) {
MyClass my_class_instance;
my_class_instance.set_a();
system("pause");
}
它只是函数的首选结构,还是存在真实的、可衡量的差异?据我所知,这两个函数在所有情况下都实现了相同的结果,除了第一个示例有多个重载,它们采用了不同类型的对象。
正如C++常见问题解答所说:尽可能使用会员,必要时使用朋友。
在某些情况下,最好将friend
函数设置为自由函数,大多数情况与成员函数的第一个参数始终属于该类(其隐藏*this
参数)有关。
一个例子是算术运算符重载:
假设您编写了一个表示复数的 complex
类。使用成员operator+()
您可以编写表达式,例如 complex + float
,但不能编写float + complex
。但是你可以用operator+
的自由形式来做到这一点:
class complex
{
...
friend complex operator+( float f , complex c );
};
整个问题归结为"我为什么要在C++中使用朋友?答案是,如果使用得当,朋友会增强封装。这是一个常见问题解答:
朋友会违反封装吗?
当然,你的例子太短太抽象了。我能想到的一些更好的、现实生活中的例子涉及迭代器。您可能有许多迭代器对象仅引用一个容器对象,并且您可能希望迭代器能够访问容器的私有成员变量。同时,您不希望容器向世界其他地方公开这些变量。
这样的设计可以通过friend
功能完美实现。
许多人认为,制作访问器方法,您可以在开发的后期阶段设置障碍,阻止对成员变量的错误访问(甚至完全更改成员变量),而不会破坏(正确的)客户端。
一个经典案例是
class ComplexNumber {
double real, imaginary;
public:
double re() { return re; }
double setRe(double v) { return re = v; }
// and so on ...
};
有一天,你发现,在一些维护中,你需要那个数字的极坐标,所以你添加了方法
double rho() { /* calculate rho */ }
double theta() { /* calculate theta */ }
double setRho(double v) { /* calculate real, imaginary, based on the new rho */ }
等等。
后来,你发现该类的用户对复数使用极坐标比笛卡尔坐标的频率要高得多,并且转换一直是性能问题的瓶颈,所以你放弃了real
和imaginary
存储rho
和theta
,并更改了新的 - 更高效 - 存储的getter和setter方法,用于rho
, theta
、re
、im
等等。类的所有客户端都可以毫无问题地重新编译,因为您更改了实现,但保持了接口稳定。
- 内联函数中具有内部链接的全局变量
- C++ SSE 内部函数:将结果存储在变量中
- 为什么从另一个构造函数内部调用C++构造函数不修改类变量?
- 是否可以禁止在for循环体内部修改循环变量
- 当使用lambda进行变量的复杂初始化时,如何处理从内部抛出的lambda外部异常
- 在变量名后声明带有 () 的非内部类型与不使用变量名的行为不同。即 std::map<int,char>x(); - 这是怎么回事?
- 使用虚拟变量对 std::vector 内部循环进行切片的最佳方法
- 访问lambda内部循环控制变量
- 如何通过从变量中获取类型来访问内部 typedef
- 解决具有嵌套模板化变量的 Visual Studio 内部编译器错误
- 内部循环的变量
- lambda内部捕获的constexpr变量失去了其constexpr-ness
- 循环时内部的C 声明和初始化变量
- 用名称为“ this”内部括号内的变量在3个不同的编译器上导致不同的结果
- 静态变量是C++中的内部变量还是外部变量
- 在没有“new”关键字的情况下实例化类会导致在堆栈或堆上创建其内部变量
- C ++奇怪的模板对内部变量的专用化
- QT c++内部变量切换
- 函数内部变量与C++中用作参数的变量之间的差异
- 设置显式链接DLL的内部变量