【问题标题】:Is it obligatory to pass classes by reference in c++在c ++中是否必须通过引用传递类
【发布时间】:2016-07-21 16:16:49
【问题描述】:

我有一个 c++ 期中考试,我们的一项任务是编写一个类,它重载 << 运算符,以便我们可以将该类的私有字段打印到 std::ostream,如下所示:

Crate c1(2600, 9500);
Crate c2;
cout << c1 << ", " << c2 << endl;

必须打印Crate weight: 2600 Crate value: 9500, Crate weight: 0 Crate value: 0

我的实现是

class Crate {
    int weight;
    int value;
public:
    Crate ():weight(0), value(0) {}
    Crate (int w, int v);
    Crate& operator+= (Crate& c);
    int operator+= (int& w);

    friend ostream& operator<< (ostream& out, Crate c) {
        out << "Crate weight: " << c.weight;
        out << " Crate value: " << c.value;
        return out;
    }
};

但是,我为重载的 &lt;&lt; 运算符获得了 0/3 分,我的解决方案和评估模板之间的唯一区别是我通过值传递 Crate c,而他们通过引用传递它。

当然,如果类有动态分配的成员变量,我将不得不通过引用传递它的实例,但这里不是这样。

我知道cppreference.com 提供的示例使用了 const 引用,但有没有严格的规定在执行此操作时必须使用 const 引用?

我了解我的解决方案将weightvalue 都复制到堆栈中,而不是仅复制指向对象的指针,但是堆栈上的+4 字节(如果是32 位系统)确实那么多是一个问题,还是我错过了更严重的事情(比如某种内存泄漏)?

我还检查了这两个解决方案的反汇编,但我找不到任何可以使我的解决方案价值零分的东西。

我也问过我的教授,但他们开始谈论将其作为const 传递,但我不明白这会如何使这个解决方案在工作方面更好/不起作用。另一位教授告诉我“这在语法上完全不正确”。但是它是用 Visual Studio 和 MinGW 编译的,所以我也无法理解。

另请注意,这是一门面向电气工程师的课程。

【问题讨论】:

  • 我不知道我是否同意它的价值为 0,但我一直听到的经验法则是,如果类型大于它的指针(基本上是任何非原始类型),则通过通过引用,除非您绝对需要修改它,否则它应该始终为 const。
  • @Carcigenicate struct Cls { int i; }; => sizeof(Cls) &lt; sizeof(Cls*) 在典型的 64 位平台上
  • 我知道运算符重载需要迭代参数为 const。但是,这些类型的技术细节超出了我的知识范围。这是一个可能有帮助的解释:stackoverflow.com/a/2828320/4775223
  • @RyanHaining 好吧,很明显,如果你的类只有一个原始字段,它会非常小。说“基本上任何非原始的”对我来说有点宽泛。
  • 顺便说一句,格雷格,保持这种态度,你可能会成为一个非常优秀的程序员。这正是我希望在新一代看到的——关注、质疑权威、独立思考和推理。

标签: c++ operator-overloading pass-by-reference


【解决方案1】:

在c++中是否必须通过引用传递类

没有。

“将其作为 const 传递”这很愚蠢,如果您是按值传递,那么如果您将参数标记为 const 对外界来说并不重要。

为了尽可能直接地回答你的问题,按价值取其他类并没有错。当对象较小时,最好按值传递。在您的情况下,典型的 64 位平台上的大小差异为 0(每个 int 2 * 4bytes 与一个 8 byte 指针)。所以你的“+4 bytes on the stack”实际上是不存在的,它的大小是一样的

我预计优化编译器会重写您的代码以按值获取Crate,即使您声明它是通过引用获取。这将是出于空间局部性的原因和易于访问的原因。如果传递了指针,则需要按照指针来获取数据成员,这增加了一个步骤。

你的教授给你0分是错误的,除非课程中有非常明确的要求,所有操作员都必须带参考参数。 const CrateCrate 的问题无关紧要。

【讨论】:

  • 感谢您在我的回答中修正错字。
【解决方案2】:

你不应该得到 0,但你也不应该得到完整的分数。

friend ostream& operator<< (ostream& out, Crate c) 

每次调用它时都会创建一个副本,这可能是低效的。为了避免那些你想通过引用传递的副本,比如

friend ostream& operator<< (ostream& out, Crate& c)

但这引入了一个新问题,您的第一个版本没有通过引用传递您需要为函数提供左值。您将无法像这样使用它

std::cout << Crate();

为了解决这个问题,我们可以通过const &amp; 获取Crate,这将避免复制并允许我们绑定到临时对象

friend ostream& operator<< (ostream& out, const Crate& c)

【讨论】:

  • 他的类包含 2 个整数。按值传递它一点也不低效。
  • @BenjaminLindley 这也困扰着我。我把它更新为可以
【解决方案3】:

学习通常是关于良好的习惯和常识,更不用说你写的小例子了。

是的,在您的情况下,按性能传递值不会改变任何事情。但这有两个问题:

  • 习惯。你应该养成知道如何传递论点的习惯。如果不需要修改且数据不应移动,则通过 const 引用传递;
  • 按照您编写的方式,您的类必须是可复制构造的。你的情况是这样,但并非总是如此。

至于作为标记的实际零 - 不要担心它。没有任何意义。

【讨论】:

  • 实际上它可能很有用。十块钱说 OP 在这方面学到的东西比他的大多数同学都多,他通过深入研究和检查代码一直到编译的输出。扯掉他们的成绩,是的,但长期有益。
猜你喜欢
  • 1970-01-01
  • 2021-05-02
  • 1970-01-01
  • 2014-05-05
  • 2016-04-22
  • 2020-04-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-08
相关资源
最近更新 更多