对相同 Class 类型的 C++ 引用公开私有成员
C++ Reference to Same Class Type Exposes Private Members
此处对此进行更长时间的讨论:Why do objects of the same class have access to each other's private data?
使用具有整数长度的 Line 对象的简单示例。 operator+
重载函数可以访问另一行的私有长度(参数 const Line &line
,也就是添加到 this
行的行)。对于非运算符重载函数 (printOtherLine
) 和友元函数 (printFriendLine
) 也是如此。再次作为参数传递的 Line 不是 this
对象。
为什么会这样?
#include <iostream>
class Line
{
public:
Line()
{
length = 0;
}
Line(int length)
{
this->length = length;
}
Line operator+(const Line &line)
{
Line newLine(this->length + line.length); // I would have thought
// this would be line.getLength()
// instead of line.length
return newLine;
}
int getLength()
{
return length;
}
void printOtherLine(const Line &otherLine){
std::cout << "Other Line: " << otherLine.length << std::endl;
}
void printLine(int lineNumber){
std::cout << "Line " << lineNumber << ": " << this->length << std::endl;
}
friend void printFriendLine(const Line &friendlyLine);
private:
int length;
};
void printFriendLine(const Line &friendlyLine){
std::cout << "Friendly Line: " << friendlyLine.length << std::endl;
}
// This function will not compile
// void printUnassociatedLine(const Line &line){
// std::cout << "Unassociated Line: " << line.length << std::endl;
// }
int main()
{
Line l1(10);
l1.printLine(1);
Line l2(15);
l2.printLine(2);
Line l3 = l1 + l2;
l3.printLine(3);
Line l4(7);
l3.printOtherLine(l4);
printFriendLine(l4);
return 0;
}
输出:
Line 1: 10
Line 2: 15
Line 3: 25
Other Line: 7
Friendly Line: 7
在 C++ 中,class X 的所有代码都可以访问 X 的所有部分,无论是哪个对象。
这甚至包括嵌套在 X 中的 class 定义中的代码。
关于我的猜测的基本原理,post-合理化,但访问限制的目的是使 class 更容易正确使用,更难以错误使用,因为其他代码。 class 自己的代码是可信的,无论如何都必须使用所有 class。因此,以任何方式限制 class' 自己的代码都没有多大意义。
关于访问 protected
数据成员有一个有趣的技术问题。在 class Base
中引入的受保护数据成员可以在派生 class Derived
中直接访问,但仅适用于静态已知类型为 Derived
或classes 来自 Derived
。这确保您不会无意中访问并使您的代码依赖于其他人的 class' 内部结构,只是通过从公共基础 class.
派生
class Base
{
protected:
int x_ = 666;
};
class Derived
: public Base
{
public:
auto uh_oh( Base const& other ) const
-> int
{ return x_ * other.x_; } //← Nyet!
};
auto main()
-> int
{
Derived a
Derived b;
return a.uh_oh( b );
}
有两种常见的解决方法,其中一种方法确实需要该访问权限。一种是在基class中引入访问函数。另一种是利用成员指针的类型系统漏洞,像这样:
class Base
{
protected:
int x_ = 666;
};
class Derived
: public Base
{
public:
auto uh_oh( Base const& other ) const
-> int
{ return x_ * other.*&Derived::x_; } // A somewhat dirty trick.
};
auto main()
-> int
{
Derived a;
Derived b;
return a.uh_oh( b );
}
这里还有一个隐含的最佳实践问题:当你有一个像getLength
这样的访问器,并且还可以访问"the"成员变量length
,应该优先使用一个还是另一个?
好吧,可能有人后来想改变实现,例如长度可能以某种方式计算而不是直接存储,如果代码通常使用访问器函数,那么这样做的工作量可能会减少。但另一方面,使用访问器编写代码可能需要更多工作,调试此类代码也可能需要更多工作。所以至少据我所知,在每种情况下都取决于常识,直觉决定。 ;-)
此处对此进行更长时间的讨论:Why do objects of the same class have access to each other's private data?
使用具有整数长度的 Line 对象的简单示例。 operator+
重载函数可以访问另一行的私有长度(参数 const Line &line
,也就是添加到 this
行的行)。对于非运算符重载函数 (printOtherLine
) 和友元函数 (printFriendLine
) 也是如此。再次作为参数传递的 Line 不是 this
对象。
为什么会这样?
#include <iostream>
class Line
{
public:
Line()
{
length = 0;
}
Line(int length)
{
this->length = length;
}
Line operator+(const Line &line)
{
Line newLine(this->length + line.length); // I would have thought
// this would be line.getLength()
// instead of line.length
return newLine;
}
int getLength()
{
return length;
}
void printOtherLine(const Line &otherLine){
std::cout << "Other Line: " << otherLine.length << std::endl;
}
void printLine(int lineNumber){
std::cout << "Line " << lineNumber << ": " << this->length << std::endl;
}
friend void printFriendLine(const Line &friendlyLine);
private:
int length;
};
void printFriendLine(const Line &friendlyLine){
std::cout << "Friendly Line: " << friendlyLine.length << std::endl;
}
// This function will not compile
// void printUnassociatedLine(const Line &line){
// std::cout << "Unassociated Line: " << line.length << std::endl;
// }
int main()
{
Line l1(10);
l1.printLine(1);
Line l2(15);
l2.printLine(2);
Line l3 = l1 + l2;
l3.printLine(3);
Line l4(7);
l3.printOtherLine(l4);
printFriendLine(l4);
return 0;
}
输出:
Line 1: 10
Line 2: 15
Line 3: 25
Other Line: 7
Friendly Line: 7
在 C++ 中,class X 的所有代码都可以访问 X 的所有部分,无论是哪个对象。
这甚至包括嵌套在 X 中的 class 定义中的代码。
关于我的猜测的基本原理,post-合理化,但访问限制的目的是使 class 更容易正确使用,更难以错误使用,因为其他代码。 class 自己的代码是可信的,无论如何都必须使用所有 class。因此,以任何方式限制 class' 自己的代码都没有多大意义。
关于访问 protected
数据成员有一个有趣的技术问题。在 class Base
中引入的受保护数据成员可以在派生 class Derived
中直接访问,但仅适用于静态已知类型为 Derived
或classes 来自 Derived
。这确保您不会无意中访问并使您的代码依赖于其他人的 class' 内部结构,只是通过从公共基础 class.
class Base
{
protected:
int x_ = 666;
};
class Derived
: public Base
{
public:
auto uh_oh( Base const& other ) const
-> int
{ return x_ * other.x_; } //← Nyet!
};
auto main()
-> int
{
Derived a
Derived b;
return a.uh_oh( b );
}
有两种常见的解决方法,其中一种方法确实需要该访问权限。一种是在基class中引入访问函数。另一种是利用成员指针的类型系统漏洞,像这样:
class Base
{
protected:
int x_ = 666;
};
class Derived
: public Base
{
public:
auto uh_oh( Base const& other ) const
-> int
{ return x_ * other.*&Derived::x_; } // A somewhat dirty trick.
};
auto main()
-> int
{
Derived a;
Derived b;
return a.uh_oh( b );
}
这里还有一个隐含的最佳实践问题:当你有一个像getLength
这样的访问器,并且还可以访问"the"成员变量length
,应该优先使用一个还是另一个?
好吧,可能有人后来想改变实现,例如长度可能以某种方式计算而不是直接存储,如果代码通常使用访问器函数,那么这样做的工作量可能会减少。但另一方面,使用访问器编写代码可能需要更多工作,调试此类代码也可能需要更多工作。所以至少据我所知,在每种情况下都取决于常识,直觉决定。 ;-)