【问题标题】:C++ Indirection in accessing members from another member从另一个成员访问成员的 C++ 间接访问
【发布时间】:2012-01-13 09:53:55
【问题描述】:

给出以下示例代码:

class Room {
    Room() : switch(*this) { }
    Lamp lamp;
    Switch switch;
    void TurnOn() { lamp.TurnOn(); }
}

class Switch {
    Switch(Room& room) : room(room) { }
    Room& room;
    void TurnOn() { room.lamp.TurnOn(); }
}

我的理解是第二个TurnOn() 涉及额外的间接级别,因为我们需要遵循对房间的引用。它是否正确?如果可以内联调用(通过显式内联或链接器级别的整个程序优化),是否会删除额外的间接调用?或者换一种说法,Switch 中的 TurnOn 功能是否可以通过将其更改为:

class Room {
    Lamp lamp;
    Switch switch;
    Room() : switch(*this,lamp) { }
    void TurnOn() { lamp.TurnOn(); }
}

class Switch {
    Room& room;
    Lamp& lamp;
    Switch(Room& room,Lamp& lamp) : room(room),lamp(lamp) { }
    void TurnOn() { lamp.TurnOn(); }
}

或者,更一般地说,如果持有对对象的引用,是否存在通过引用直接访问其成员而不是先通过引用再访问成员的间接级别?

谢谢

【问题讨论】:

  • switch 是关键字,不能作为变量使用。
  • 不要使用 switch(实际上,你不能。它是为 switch 构造保留的。)
  • 抱歉,选错了一个例子……我显然在考虑电灯开关
  • 如有疑问,请测量。除非你有具体的理由,否则不要以性能的名义丑化你的代码。

标签: c++ indirection


【解决方案1】:

它可能会更快(虽然不是很多)。但是,这两个示例都是不正确的,因为它们破坏了封装并违反了Law of Demeter。他们要求Switch 类或实例化它的任何人都可以访问Room 本身和其中的Lamp。当然,我们还假设每个房间都有一盏灯,并且一盏灯只能存在于一个房间内......这意味着如果这些条件发生变化,有两个类要改变,而不仅仅是一个。

第一个例子最好写成

class Room {
  public:
    Room() : sw(*this) { }
    void TurnOn() { lamp.TurnOn(); }
  private:
    Lamp lamp;
    Switch sw;
};

class Switch {
  public:
    Switch(Room& room) : room(room) { }
    void TurnOn() { room.TurnOn(); }
  private:
    Room& room;
};

然后Room 负责打开的内容。可以是台灯,也可以是收音机。 Switch 不必再关心了。这可能会更慢,但更易于维护。

如果你想要求Switch 只打开一个Lamp,那么

class Room {
  public:
    Room() : sw(lamp) { }
    void TurnOn() { lamp.TurnOn(); } // (semantics: who "turns on" a room?)
  private:
    Lamp lamp;
    Switch sw;
};

class Switch {
  public:
    Switch(Lamp& lamp) : lamp(lamp) { }
    void TurnOn() { lamp.TurnOn(); }
  private:
    Lamp& lamp;
};

这应该同样快,而不需要我们打破封装。

【讨论】:

    【解决方案2】:

    您的第二个示例(可能)不会比第一个示例快。在这两种情况下,都需要先解析一个引用,然后才能调用 TurnOn()。

    【讨论】:

    • 我认为它是实现定义的。编译器可以简单地使用原始对象,而不是引用。
    • @Nawaz:如果可以内联内容,那么可以,我同意;编译器可以进行各种优化。但在所有其他条件相同的情况下,OP 的示例都没有比其他示例更可优化。
    • 从引用指向的对象调用 TurnOn 不应该有优势吗?例如,运行时解析应该不是必需的,并且该间接级别应该在编译时可以解析?
    • @Cookie:在这两种情况下,都需要解析引用(第一种是Room &room;第二种是Lamp &lamp)。
    • 我明白了,确实如此。相当糟糕的问题。因此,如果从 Room 中调用这些函数中的任何一个,它们会在未内联时涉及额外的间接,但经过优化,该间接可能会再次被删除?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    • 2013-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-29
    相关资源
    最近更新 更多