为什么我可以从其他对象访问这个私有成员?

Why can I access this private member from an other object?

我目前正在从 Stroustrup 的《编程:原理与实践》学习 C++,但有一个我无法真正理解的示例。有一个叫做 Link 的 class 看起来像这样。

class Link{

public:

    Link(Link* p=nullptr, Link* n=nullptr, const std::string& label);
    Link* erase();

private:
    std::string label;
    Link* succ;
    Link* prev;

};


Link* Link::erase() {

    if (this ==  nullptr) return nullptr;

    if(prev) prev->succ = succ;
    if(succ) succ->prev = prev;

    return succ;


}

我不明白的是为什么 prev->succ = succ; 是正确的,因为我正在从另一个对象分配给一个对象的私有成员。我在这里错过了什么?

因为私有成员对class是私有的,而不仅仅是实例

因此 Link 的实例可以看到彼此的私人成员,而不仅仅是他们自己的。

你可以问自己一个问题,复制构造函数是如何工作的。

封装是针对 classes,而不是对象。

封装是"hide"代码到class之外的一种方式。在 class 中,可以访问每个私有字段和函数。这不是一种保护对象的方法,它是一种隐藏实现的方法,class 的用户不需要知道它们以提高开发效率。

访问限制适用于名称,不适用于对象。

来自[class.access]

A member of a class can be

  • private; that is, its name can be used only by members and friends of the class in which it is declared.

  • protected; that is, its name can be used only by members and friends of the class in which it is declared, by classes derived from that class, and by their friends (see [class.protected]).

  • public; that is, its name can be used anywhere without access restriction.

(强调)

按 class 而非按对象进行访问。如果访问是按实例进行的,许多事情将不会像它们那样工作。比如这个类型

class foo {
    int x;
};

编译器生成的复制构造函数是这样的:

foo::foo(const foo& other) {
    x = other.x;
}

访问限制是为了封装,而封装是为了确保不违反 class 不变量。但是,通常在方法内部会暂时违反不变量。例如考虑这个 class

class Sum {
    int a = 0;
    int b = 0;
    int sum = 0;
public:
    void set(int x,int y);
    int get_sum() { return sum; }
};

这里的不变量是 sum 总是 ab 的总和。但是,在 set 方法中...

void Sum::set(int x,int y) {
    a = x;
    b = y;
    sum = a + b;
}

这个不变量只在最后一行恢复。您有责任恢复不变量,使其在外部看来始终成立。

此外,访问限制是为了隐藏实现细节。在 Sum 示例中,用户不知道成员 sum 存在并且他们不需要知道它。但是,class 方法的定义与实现细节有关。处理不同对象的实现细节没有区别,因为它们是相同的。

与你的例子有什么关系?

访问限制的目的是让您确保从不违反外部不变量并隐藏实现细节。在 Link 的方法中,您必须知道自己在做什么。您必须知道 prevsucc 的含义,无论是 this 的成员还是其他对象。该方法必须确保不违反不变量:在调用 erase 之后,调用者仍然有一个有效的 Link。为此,您需要处理实现细节:有效的 Linkprecsucc

结论:无法访问其他对象的私有方法将是一个主要障碍,并不能真正带来优势(因为无论如何在方法内部你已经在处理 class 和你经常会暂时违反不变量)。