C ++对同一类类型的引用暴露了私有成员

时间:2016-07-16 23:36:51

标签: c++ oop pass-by-reference 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 object。

为什么会这样?

#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

1 个答案:

答案 0 :(得分:0)

在C ++中,无论使用哪个对象,X类的所有代码都可以访问X的所有部分。

这甚至包括嵌套在X中的类定义中的代码。

关于我所知道的推理理由,后合理化,但访问限制的目的是使一个类更容易正确使用,更难以正确使用,对于其他代码。班级&#39;自己的代码是可信的,无论如何都必须使用所有类。因此限制课程并没有多大意义。以任何方式拥有自己的代码。

关于访问protected数据成员存在一个有趣的技术问题。类Base中引入的受保护数据成员可以直接在派生类Derived中访问,但仅适用于静态已知类型为Derived的对象或从Derived派生的类。这可以确保您不会无意中获取访问权限,并使您的代码依赖于其他人的课程&#39;内部,只是来自一个共同的基类。

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 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之类的访问者,并且还可以访问&#34;&#34;成员变量length,是否应该优先使用其中一个?

嗯,可能是后来人们希望改变实施,例如长度可能以某种方式计算而不是直接存储,如果代码通常使用访问器函数,那么这样做的工作就更少了。但另一方面,使用访问器编写代码可能需要做更多工作,调试此类代码可能需要做更多工作。所以至少就我所知,在每种情况下都是常识,直觉决定。 ; - )